Musterlösung für die Implementierung eines Schwarms in Java basierend auf gleitenden Scheiben
  | 
java_puck2.zip - Download der folgenden Java-Programme
Dynamisches Modell einer passiven gleitenden Scheibe
Bild 0-1: Simulationsmodell für eine passive gleitende Scheibe mit Dämpfung der Bewegung
  | 
Objektorientierte Umsetzung ohne Visualisierung mit Java unter Verwendung eines Runge-Kutta-Integrators
  | 
import java.io.*;
import java.util.*;
public class Hauptprogramm
{
    private int    puck_anzahl = 10;
    private double t  = 0.0;
    private double dt = 0.1;
    private int schritte = 10000;
    public Modell[] modell;
    public Integrator[] integrator;
    private int iabs(int x)
    {
        if(x<0)
            return -x;
        else
            return x;
    }
    public void init()
    {
        //Erzeugen aller Modelle
        modell = new Modell[puck_anzahl];
        for(int i=0;i<puck_anzahl;i++)
            modell[i] = new Modell();
        Random random = new Random(0);
        //Zufällige Anfangsbedingungen für die Pucks setzen:
        for(int i=0;i<puck_anzahl;i++)
        {
            modell[i].yalt[0] =  (double)(50 + iabs(random.nextInt())%400);
            modell[i].yalt[1] =  0.001*(double)(iabs(random.nextInt())%2000 - 1000);
            modell[i].yalt[2] =  (double)(50 + iabs(random.nextInt())%400);
            modell[i].yalt[3] =  0.001*(double)(iabs(random.nextInt())%2000 - 1000);
        }
        //Erzeugen der zugehörigen Integratoren
        integrator = new Integrator[puck_anzahl];
        for(int i=0;i<puck_anzahl;i++)
            integrator[i] = new Integrator(modell[i]);
    }
    private void zeitschritt()
    {
        for(int i=0;i<puck_anzahl;i++) //alle Pucks durchgehen
        {
            integrator[i].zeitschritt(t,dt);
        }
    }
    public void simulieren()
    {
        for(int i=0;i<schritte;i++)
        {
            System.out.print(""+t);
            for(int k=0;k<puck_anzahl;k++)
            {
                //Für Scilab Zeit und dann alle Koordinaten zeilenweise ausgeben
                System.out.print(" "+modell[k].yalt[0]+" "+modell[k].yalt[2]);
                integrator[k].zeitschritt(t,dt);
            }
            System.out.println();
            t+=dt;
        }
    }
    public static void main(String[] args)
    {
        Hauptprogramm hp = new Hauptprogramm();
        hp.init();
        hp.simulieren();
    }
}
Code 0-1: Quellcode zu Hauptprogramm.java in puck01_passiv
public class Modell
{
    public double[] param = {1.0,0.001};
    public double[] yalt; //Im Modell den letzten Zustand merken
    private int anzahl=4;
    private  double m;
    private  double D;    
    private double f;
    public Modell()  
    {  
        yalt = new double[anzahl];      
    }
    public double rechteSeite(double[] y,double t, int zeile)
    {
        m = param[0];
        D = param[1];
        switch(zeile)
        {
            case 0:
                f = y[1];
            break;
            case 1:
                f = -(D/m)*y[1]; 
            break;                    
            case 2:
                f = y[3];
            break;                    
            default:
                f = -(D/m)*y[3]; 
            break;                                                                                            
        }              
        return f; 
    }
    public int holeAnzahlGleichungen()
    {
        return anzahl;
    } 
} 
Code 0-2: Quellcode zu Modell.java in puck01_passiv
//Integrator, der ein Runge-Kutta-Verfahren verwendet.
//Bei Aufruf des Konstruktors wird ein Zeiger auf das zu integrierende Modell im 
//Integrator-Objekt gespeichert.
public class Integrator
{
    private Modell modell;
    private double[] yneu;
    private double[] yhilf;
    private double[] k1,k2,k3,k4;
    public Integrator(Modell modell)
    {
        this.modell = modell;
        yneu = new double[modell.holeAnzahlGleichungen()];
        yhilf = new double[modell.holeAnzahlGleichungen()];
        k1 = new double[modell.holeAnzahlGleichungen()]; 
        k2 = new double[modell.holeAnzahlGleichungen()]; 
        k3 = new double[modell.holeAnzahlGleichungen()]; 
        k4 = new double[modell.holeAnzahlGleichungen()]; 
    }
    void zeitschritt(double t,double dt)
    {
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k1[i] = modell.rechteSeite(modell.yalt,t,i);
            yhilf[i] = modell.yalt[i] + 0.5*dt*k1[i];
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k2[i] = modell.rechteSeite(yhilf,t,i);
            yhilf[i] = modell.yalt[i] + 0.5*dt*k2[i];
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k3[i] = modell.rechteSeite(yhilf,t,i);
            yhilf[i] = modell.yalt[i] + dt*k3[i];
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k4[i] = modell.rechteSeite(yhilf,t,i);
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            yneu[i] = modell.yalt[i] + (dt/6.0)*(k1[i]+2.0*k2[i]+2.0*k3[i]+k4[i]);
        }                
        //Neuen y-Wert als alten im Modell speichern:
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
            modell.yalt[i] = yneu[i];
    }     
}
Code 0-3: Quellcode zu Integrator.java in puck01_passiv
  | 
m=fscanfMat('test.txt');
//plot(m(:,1),sqrt(m(:,2).*m(:,2)+m(:,5).*m(:,5)));
plot(m(:,2),m(:,3),m(:,4),m(:,5), ... ,m(:,20),m(:,21));
Code 0-4: Skript, um folgende Ergebnisse zu zeigen.
Bild 0-2: Zurückgelegter Weg im Betrag von Puck Nr. 0 (Es ist die Dämpfung erkennbar)
Bild 0-3: Zurückgelegter Weg aller 10 simulierten Puck-Elemente in der Ebene
Ergänzen von Kollision
  | 
Bild 0-4: Ergänzung der dynamischen Gleichungen durch einen Term, der für jeden Puck bei durchdringen eines anderen Pucks proportional zu der Durchdringungstiefe eine Gegenkraft erzeugt.
  | 
public class Modell
{
    public Modell[] puck;
    public static int zaehler=0; //Zählt wieviele Pucks bereits erzeugt wurden.
    public int nr; //Nummer des aktuellen Pucks 
    public double[] param = {1.0,0.001,30.0,20.0};
    public double[] yalt; //Im Modell den letzten Zustand merken
    public double[] yneu; //Veränderten Zustand innerhalb eines Zeitschritts auch merken.
    private int anzahl=4;
    private  double m;
    private  double D;
    private  double K;
    private  double R; //Puckradius
    private double f;
    public Modell(Modell[] puck)  
    {  
        this.puck = puck; //Alle Pucks in jedem Puck-Objekt registrieren.
        yalt = new double[anzahl];      
        yneu = new double[anzahl];      
        nr=zaehler;  //Aktuell erstelltem Puck eine Nummer zuweisen.
        zaehler++;   //In statischer Variablen mitzaehlen, wieviele Pucks schon erstellt wurden.
    }
    public double rechteSeite(double[] y,double t, int zeile)
    {
        m = param[0];
        D = param[1];
        K = param[2];
        R = param[3];
        //Durch Kollisionen entstehende Zusatzkraft bestimmen.
        //Alle anderen Pucks durchgehen.
        double x_koll=0.0;
        double y_koll=0.0;
        for(int i=0;i<puck.length;i++)
        {
            if(i!=nr) //nur wenn Auswahl nicht aktueller Puck selbst ist.
            {
                double x1 = yalt[0];
                double y1 = yalt[2];
                double x2 = puck[i].yalt[0];
                double y2 = puck[i].yalt[2];
                double betrag = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); //Distanz der Puck-Mittelpunkte nr und i
                if(betrag<2.0*R && betrag!=0.0)
                {
                    //Richtungsvektor bestimmen:
                    double ex = (x1-x2)/betrag;
                    double ey = (y1-y2)/betrag;
                    //Kraft hinzuaddieren:
                    x_koll += K*(2.0*R-betrag)*ex;
                    y_koll += K*(2.0*R-betrag)*ey;
                }
            }
        }
        switch(zeile)
        {
            case 0:
                f = y[1];
            break;
            case 1:
                f = -(D/m)*y[1]+x_koll/m; 
            break;                    
            case 2:
                f = y[3];
            break;                    
            default:
                f = -(D/m)*y[3]+y_koll/m; 
            break;                                                                                            
        }              
        return f; 
    }
    public int holeAnzahlGleichungen()
    {
        return anzahl;
    } 
} 
Code 0-5: Modell.java in puck02_kollision
import java.io.*;
import java.util.*;
public class Hauptprogramm
{
    private int    puck_anzahl = 10;
    private double t  = 0.0;
    private double dt = 0.1;
    private int schritte = 10000;
    public Modell[] modell;
    public Integrator[] integrator;
    private int iabs(int x)
    {
        if(x<0)
            return -x;
        else
            return x;
    }
    public void init()
    {
        //Erzeugen aller Modelle
        modell = new Modell[puck_anzahl];
        for(int i=0;i<puck_anzahl;i++)
            modell[i] = new Modell(modell);
        Random random = new Random(0);
        //Zufällige Anfangsbedingungen für die Pucks setzen:
        for(int i=0;i<puck_anzahl;i++)
        {
            modell[i].yalt[0] =  (double)(50 + iabs(random.nextInt())%400);
            modell[i].yalt[1] =  0.001*(double)(iabs(random.nextInt())%2000 - 1000);
            modell[i].yalt[2] =  (double)(50 + iabs(random.nextInt())%400);
            modell[i].yalt[3] =  0.001*(double)(iabs(random.nextInt())%2000 - 1000);
        }
        //Erzeugen der zugehörigen Integratoren
        integrator = new Integrator[puck_anzahl];
        for(int i=0;i<puck_anzahl;i++)
            integrator[i] = new Integrator(modell[i]);
    }
    public void simulieren()
    {
        for(int i=0;i<schritte;i++)
        {
            System.out.print(""+t);
            for(int k=0;k<puck_anzahl;k++)
            {
                //Für Scilab Zeit und dann alle Koordinaten zeilenweise ausgeben
                System.out.print(" "+modell[k].yalt[0]+" "+modell[k].yalt[2]);
                integrator[k].zeitschritt(t,dt);
            }
            //alle neuen Zustaende als alte umkopieren vorbereitend auf den nächsten Integrationsschritt:
            for(int ii=0;ii<puck_anzahl;ii++) //alle Pucks durchgehen
            {
                for(int k=0;k<modell[ii].yneu.length;k++)
                    modell[ii].yalt[k] = modell[ii].yneu[k];
            }
            System.out.println();
            t+=dt;
        }
    }
    public static void main(String[] args)
    {
        Hauptprogramm hp = new Hauptprogramm();
        hp.init();
        hp.simulieren();
    }
}
Code 0-6: Hauptprogramm.java in puck02_kollision
//Integrator, der ein Runge-Kutta-Verfahren verwendet.
//Bei Aufruf des Konstruktors wird ein Zeiger auf das zu integrierende Modell im 
//Integrator-Objekt gespeichert.
public class Integrator
{
    private Modell modell;
    private double[] yneu;
    private double[] yhilf;
    private double[] k1,k2,k3,k4;
    public Integrator(Modell modell)
    {
        this.modell = modell;
        yneu = new double[modell.holeAnzahlGleichungen()];
        yhilf = new double[modell.holeAnzahlGleichungen()];
        k1 = new double[modell.holeAnzahlGleichungen()]; 
        k2 = new double[modell.holeAnzahlGleichungen()]; 
        k3 = new double[modell.holeAnzahlGleichungen()]; 
        k4 = new double[modell.holeAnzahlGleichungen()]; 
    }
    void zeitschritt(double t,double dt)
    {
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k1[i] = modell.rechteSeite(modell.yalt,t,i);
            yhilf[i] = modell.yalt[i] + 0.5*dt*k1[i];
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k2[i] = modell.rechteSeite(yhilf,t,i);
            yhilf[i] = modell.yalt[i] + 0.5*dt*k2[i];
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k3[i] = modell.rechteSeite(yhilf,t,i);
            yhilf[i] = modell.yalt[i] + dt*k3[i];
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            k4[i] = modell.rechteSeite(yhilf,t,i);
        }                
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
        {
            yneu[i] = modell.yalt[i] + (dt/6.0)*(k1[i]+2.0*k2[i]+2.0*k3[i]+k4[i]);
        }                
        //Neuen y-Wert als neuen im Modell speichern (später umkopieren):
        for(int i=0;i<modell.holeAnzahlGleichungen();i++)
            modell.yneu[i] = yneu[i];
    }     
}
Code 0-7: Integrator.java in puck02_kollision
Bild 0-5: Resultat nach Ergänzung der Kollisionskräfte im Programm.