Ich löse Turings Reaktionsdiffusionssystem mit folgendem C ++ - Code. Es ist zu langsam: Für eine Textur mit 128 x 128 Pixeln beträgt die akzeptable Anzahl von Iterationen 200 - was zu einer Verzögerung von 2,5 Sekunden führt. Ich benötige 400 Iterationen, um ein interessantes Bild zu erhalten - aber 5 Sekunden Warten sind zu viel. Außerdem sollte die Größe der Textur tatsächlich 512 x 512 betragen - dies führt jedoch zu einer enormen Wartezeit. Die Geräte sind iPad, iPod.
Gibt es eine Chance, dies schneller zu tun? Die Euler-Methode konvergiert langsam (Wikipedia) - eine schnellere Methode würde es ermöglichen, die Anzahl der Iterationen zu verringern?
EDIT: Wie Thomas Klimpel betonte, lauten die Zeilen: "if (m_An [i] [j] <0.0) {...}", "if (m_Bn [i] [j] <0.0) {...}" verzögern die Konvergenz: Nach dem Entfernen erscheint nach 75 Iterationen ein aussagekräftiges Bild . Ich habe die Zeilen im Code unten auskommentiert.
void TuringSystem::solve( int iterations, double CA, double CB ) {
m_iterations = iterations;
m_CA = CA;
m_CB = CB;
solveProcess();
}
void set_torus( int & x_plus1, int & x_minus1, int x, int size ) {
// Wrap "edges"
x_plus1 = x+1;
x_minus1 = x-1;
if( x == size - 1 ) { x_plus1 = 0; }
if( x == 0 ) { x_minus1 = size - 1; }
}
void TuringSystem::solveProcess() {
int n, i, j, i_add1, i_sub1, j_add1, j_sub1;
double DiA, ReA, DiB, ReB;
// uses Euler's method to solve the diff eqns
for( n=0; n < m_iterations; ++n ) {
for( i=0; i < m_height; ++i ) {
set_torus(i_add1, i_sub1, i, m_height);
for( j=0; j < m_width; ++j ) {
set_torus(j_add1, j_sub1, j, m_width);
// Component A
DiA = m_CA * ( m_Ao[i_add1][j] - 2.0 * m_Ao[i][j] + m_Ao[i_sub1][j] + m_Ao[i][j_add1] - 2.0 * m_Ao[i][j] + m_Ao[i][j_sub1] );
ReA = m_Ao[i][j] * m_Bo[i][j] - m_Ao[i][j] - 12.0;
m_An[i][j] = m_Ao[i][j] + 0.01 * (ReA + DiA);
// if( m_An[i][j] < 0.0 ) { m_An[i][j] = 0.0; }
// Component B
DiB = m_CB * ( m_Bo[i_add1][j] - 2.0 * m_Bo[i][j] + m_Bo[i_sub1][j] + m_Bo[i][j_add1] - 2.0 * m_Bo[i][j] + m_Bo[i][j_sub1] );
ReB = 16.0 - m_Ao[i][j] * m_Bo[i][j];
m_Bn[i][j] = m_Bo[i][j] + 0.01 * (ReB + DiB);
// if( m_Bn[i][j] < 0.0 ) { m_Bn[i][j]=0.0; }
}
}
// Swap Ao for An, Bo for Bn
swapBuffers();
}
}
Antworten:
Sie scheinen durch die Stabilität eingeschränkt zu sein, was zu erwarten ist, da die Diffusion beim Verfeinern des Gitters steif ist. Gute Methoden für steife Systeme sind zumindest teilweise implizit. Es wird einige Mühe kosten, aber Sie können einen einfachen Multigrid-Algorithmus implementieren (oder eine Bibliothek verwenden), um dieses System mit Kosten von weniger als zehn "Arbeitseinheiten" (im Wesentlichen den Kosten eines Ihrer Zeitschritte) zu lösen. Wenn Sie das Raster verfeinern, wird die Anzahl der Iterationen nicht erhöht.
quelle
Aus praktischer Sicht: Der A5-Prozessor ist nicht sehr leistungsfähig, sodass Sie einige HW-Iterationen abwarten können. Wenn Ihr iPod / iPad mit dem Internet verbunden werden soll, lösen Sie Ihr Problem remote oder in der Cloud.
quelle
Euler konvergiert zwar langsam in Bezug auf andere Methoden, aber ich denke nicht, dass Sie daran interessiert sind. Wenn Sie nur nach "interessanten" Bildern suchen, vergrößern Sie Ihren Zeitschritt und führen Sie weniger Iterationen durch. Jed weist darauf hin, dass das Problem darin besteht, dass die explizite Eulermethode Stabilitätsprobleme mit großen Zeitschritten in Bezug auf die Gittergröße aufweist. Je kleiner Ihr Raster ist (dh je höher die Auflösung Ihres Bildes ist), desto kleiner muss Ihr Zeitschritt sein, um dies zu berücksichtigen.
Wenn Sie beispielsweise implizites Euler anstelle von explizit verwenden, erhalten Sie keine Konvergenzreihenfolgen, aber die Lösung weist eine bedingungslose Stabilität auf, die viel größere Zeitschritte ermöglicht. Implizite Methoden sind komplizierter zu implementieren und erfordern mehr Berechnungen pro Zeitschritt. Sie sollten jedoch weit darüber hinaus Gewinne erzielen, wenn Sie insgesamt weniger Schritte ausführen.
quelle