Metodo di Eulero esplicito troppo lento per il problema di diffusione della reazione


10

Sto risolvendo il sistema di reazione-diffusione di Turing con il seguente codice C ++. È troppo lento: per una trama di 128x128 pixel, il numero accettabile di iterazioni è 200, il che comporta un ritardo di 2,5 secondi. Ho bisogno di 400 iterazioni per ottenere un'immagine interessante, ma 5 secondi di attesa sono troppi. Inoltre, la dimensione della trama dovrebbe essere in realtà 512x512, ma ciò comporta enormi tempi di attesa. I dispositivi sono iPad, iPod.

C'è qualche possibilità di farlo più velocemente? Il metodo di Eulero converge lentamente (wikipedia) - avere un metodo più veloce consentirebbe di eliminare il numero di iterazioni?

EDIT: Come ha sottolineato Thomas Klimpel, le righe: "if (m_An [i] [j] <0.0) {...}", "if (m_Bn [i] [j] <0.0) {...}" ritardano la convergenza: dopo la rimozione, l'immagine significativa appare dopo 75 iterazioni . Ho commentato le righe nel codice qui sotto.

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();
    }
}

Inoltre, voglio menzionare che è preferibile non porre domande incrociate, poiché sembra che tu abbia posto domande molto simili sia qui che qui .
Godric Seer,

Hai già visto il lavoro di Greg Turk su questo, per caso?
JM,

@JM: non ancora. Ho appena provato a eseguire il suo codice: richiede un server X con PseudoColor, ovvero una profondità di colore a 8 bit. Penso di non poterlo fornire su OSX. Ho provato vari server VNC ma senza fortuna.
AllCoder

Penso che dovresti essere ancora in grado di adattare l'approccio di Turk all'argomento in questione; Al giorno d'oggi i modelli di reazione-diffusione sembrano essere usati un po 'nella grafica computerizzata.
JM,

1
Potrei sbagliarmi, ma la parte con m_An [i] [j] = 0.0; potrebbe effettivamente aggiungere un elemento a questo sistema che non può essere modellato da un'equazione differenziale con un lato destro continuo. Questo rende un po 'difficile trovare un risolutore più veloce.
Thomas Klimpel,

Risposte:


9

Sembra che tu sia limitato dalla stabilità, che è prevista poiché la diffusione è rigida mentre perfezioni la griglia. I buoni metodi per i sistemi rigidi sono almeno parzialmente impliciti. Ci vorrà un po 'di sforzo, ma è possibile implementare un semplice algoritmo multigrid (o utilizzare una libreria) per risolvere questo sistema con un costo inferiore a dieci "unità di lavoro" (essenzialmente il costo di una delle fasi temporali). Quando si perfeziona la griglia, il numero di iterazioni non aumenta.


Se solo la diffusione fosse rigida qui, potrebbe usare un metodo ADI come Douglas-Gunn e tutto andrebbe bene. Tuttavia, secondo la mia esperienza, la parte della reazione è spesso molto peggiore rispetto alla rigidità oltre ad essere gravemente non lineare.
Thomas Klimpel,

1
Purtroppo ADI ha una terribile località di memoria. Si noti inoltre che la reazione può essere trattata implicitamente indipendentemente dalla diffusione. Sotto il perfezionamento della griglia, la diffusione diventerà alla fine dominante, ma non possiamo dire dove sia la soglia senza conoscere le costanti.
Jed Brown,

Esempio di codice per implementare Euler all'indietro per questo (in Python) è qui: scicomp.stackexchange.com/a/2247/123
David Ketcheson il

@DavidKetcheson: l'utilizzo di metodi impliciti richiede la risoluzione di un'equazione? Questo è il motivo per cui nel codice è presente linalg.spsolve ()?
AllCoder

1
@AllCoder Sì, richiede una risoluzione, ma la risoluzione può essere eseguita molto più velocemente di tutte le fasi temporali necessarie per rendere stabile un metodo esplicito.
Jed Brown,

2

Da un punto di vista pratico: il processore A5 non è molto potente, quindi puoi aspettare alcune iterazioni HW o se il tuo ipod / ipad sarà connesso a Internet, risolvi il tuo problema da remoto o nel cloud.


Sono sorpreso dal potere ridotto offerto dalla A5. Come possono funzionare così bene Pages, Safari e altre applicazioni di grandi dimensioni? Ho bisogno di generare immagini casuali, astratte, pensato che la morfogenesi sarà abbastanza semplice ..
AllCoder

Bene, A5 è un processore ad alta efficienza energetica ottimizzato per web e video (Pages, Safari, ecc.). Al contrario, la maggior parte dei carichi di lavoro numerici esegue tonnellate di operazioni in virgola mobile e movimenti di dati, queste caratteristiche non sono al centro di un processore mobile a bassa potenza.
fcruz,

0

Euler converge lentamente in relazione ad altri metodi, tuttavia non penso che sia quello che ti interessa. Se stai solo cercando immagini "interessanti", aumenta le dimensioni del tuo passo temporale e fai meno iterazioni. Il problema, come sottolinea Jed, è che il metodo di espulsione esplicita presenta problemi di stabilità con grandi intervalli di tempo in relazione alle dimensioni della griglia. più piccola è la griglia (ovvero maggiore è la risoluzione dell'immagine), minore deve essere il passo temporale per tenerne conto.

Ad esempio, utilizzando l'euler implicito anziché esplicito, non si ottiene alcun ordine di convergenza, ma la soluzione avrà una stabilità incondizionata, consentendo intervalli di tempo molto più ampi. I metodi impliciti sono più complicati da implementare e richiedono più calcoli per fase temporale, ma dovresti vedere guadagni ben oltre facendo meno passaggi in totale.


Questo problema è limitato dalla stabilità, quindi semplicemente aumentare le dimensioni del passo temporale non funzionerà.
Jed Brown,

Se cambio 0,01 ad es. 0,015, allora ottengo "concentrazione di chem. Sp. Vicino allo zero" in tutti i punti, ovvero un quadrato grigio. Ecco l'origine del mio codice: drdobbs.com/article/print?articleId=184410024
AllCoder

Sì, sarebbe il risultato dei problemi di stabilità menzionati da Jed. Come accenna nella sua risposta, l'utilizzo di un metodo implicito caratterizzato da migliori prestazioni di stabilità risolverà questo problema per te. Aggiornerò la mia risposta per rimuovere le informazioni irrilevanti.
Godric Seer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.