El método explícito de Euler es demasiado lento para el problema de reacción-difusión


10

Estoy resolviendo el sistema de reacción-difusión de Turing con el siguiente código C ++. Es demasiado lento: para una textura de 128x128 píxeles, el número aceptable de iteraciones es 200, lo que resulta en 2.5 segundos de retraso. Necesito 400 iteraciones para obtener una imagen interesante, pero 5 segundos de espera es demasiado. Además, el tamaño de la textura debería ser de hecho 512x512, pero esto da como resultado un gran tiempo de espera. Los dispositivos son iPad, iPod.

¿Hay alguna posibilidad de hacer esto más rápido? El método de Euler converge lentamente (wikipedia). ¿Tener un método más rápido permitiría eliminar varias iteraciones?

EDITAR: Como señaló Thomas Klimpel, las líneas: "if (m_An [i] [j] <0.0) {...}", "if (m_Bn [i] [j] <0.0) {...}" están retrasando la convergencia: después de eliminar, aparece una imagen significativa después de 75 iteraciones . He comentado las líneas en el código a continuación.

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

Además, quiero mencionar que es preferible que no haga preguntas cruzadas, ya que parece que ha hecho preguntas muy similares aquí y aquí .
Godric Seer

¿Ya has visto el trabajo de Greg Turk en esto, por casualidad?
JM

@JM: Todavía no. Acabo de intentar ejecutar su código: requiere un servidor X con PseudoColor, es decir, profundidad de color de 8 bits. Creo que no puedo proporcionar esto en OSX. Probé varios servidores VNC pero no tuve suerte.
AllCoder

Creo que aún debería poder adaptar el enfoque de Turk al asunto en cuestión; Los patrones de reacción-difusión parecen usarse bastante en los gráficos de computadora hoy en día.
JM

1
Podría estar equivocado, pero la parte con m_An [i] [j] = 0.0; en realidad podría agregar un elemento a este sistema que no pueda ser modelado por una ecuación diferencial con un lado derecho continuo. Esto hace que sea un poco difícil encontrar un solucionador más rápido.
Thomas Klimpel

Respuestas:


9

Parece estar limitado por la estabilidad, que se espera ya que la difusión es rígida a medida que refina la cuadrícula. Los buenos métodos para sistemas rígidos son al menos parcialmente implícitos. Tomará un poco de esfuerzo, pero puede implementar un algoritmo simple de múltiples cuadrículas (o usar una biblioteca) para resolver este sistema con un costo de menos de diez "unidades de trabajo" (esencialmente el costo de uno de sus pasos de tiempo). Cuando refina la cuadrícula, el número de iteraciones no aumentará.


Si solo la difusión fuera rígida aquí, podría usar un método ADI como Douglas-Gunn y todo estaría bien. Sin embargo, en mi propia experiencia, la parte de reacción es a menudo mucho peor con respecto a la rigidez, además de ser muy no lineal.
Thomas Klimpel

1
ADI desafortunadamente tiene una localidad de memoria terrible. También tenga en cuenta que la reacción puede tratarse implícitamente independientemente de si la difusión es. Bajo el refinamiento de la cuadrícula, la difusión eventualmente se volverá dominante, pero no podemos saber dónde está el umbral sin conocer las constantes.
Jed Brown

El código de ejemplo que implementa Euler hacia atrás para esto (en Python) está aquí: scicomp.stackexchange.com/a/2247/123
David Ketcheson el

@DavidKetcheson: ¿Usar métodos implícitos requiere resolver una ecuación? ¿Es por eso que hay linalg.spsolve () en el código?
AllCoder

1
@ AllCoder Sí, requiere una solución, pero la solución se puede hacer mucho más rápido que todos los pasos de tiempo necesarios para que un método explícito sea estable.
Jed Brown

2

Desde un punto de vista práctico: el procesador A5 no es tan potente, por lo que puede esperar algunas iteraciones de HW, o si su ipod / ipad va a estar conectado a Internet, resuelva su problema de forma remota o en la nube.


Me sorprende la pequeña potencia que ofrece el A5. ¿Cómo pueden funcionar tan bien Pages, Safari y otras aplicaciones grandes? Necesito generar imágenes aleatorias y abstractas, pensé que la morfogénesis será lo suficientemente simple ...
AllCoder

Bueno, A5 es un procesador de bajo consumo de energía optimizado para web y video (Páginas, Safari, etc.). En contraste, la mayoría de las cargas de trabajo numéricas realizan toneladas de operaciones de punto flotante y movimientos de datos, estas características no son el foco de un procesador móvil de baja potencia.
fcruz

0

Euler converge lentamente en relación con otros métodos, sin embargo, no creo que eso sea lo que le interesa. Si solo está buscando imágenes "interesantes", aumente el tamaño de su paso de tiempo y tome menos iteraciones. El problema, como señala Jed, es que el método euler explícito tiene problemas de estabilidad con grandes pasos de tiempo en relación con el tamaño de la cuadrícula. cuanto más pequeña sea su cuadrícula (es decir, cuanto mayor sea la resolución de su imagen), más pequeño debe ser su paso de tiempo para tenerla en cuenta.

Por ejemplo, al usar euler implícito en lugar de explícito, no obtienes ningún orden de convergencia, pero la solución tendrá una estabilidad incondicional, permitiendo pasos de tiempo mucho más largos. Los métodos implícitos son más complicados de implementar y requieren más cómputo por paso de tiempo, pero debería ver ganancias mucho más allá de eso al tomar menos pasos en total.


Este problema está limitado por la estabilidad, por lo que simplemente no aumentará el tamaño del paso de tiempo.
Jed Brown

Si cambio 0.01 a, por ejemplo, 0.015, entonces obtengo "concentración de quimica sp. Cerca de cero" en todos los puntos, es decir, un cuadrado gris. Aquí está el origen de mi código: drdobbs.com/article/print?articleId=184410024
AllCoder

Sí, eso sería el resultado de los problemas de estabilidad que mencionó Jed. Como menciona en su respuesta, el uso de un método implícito caracterizado por un mejor rendimiento de estabilidad resolverá este problema por usted. Actualizaré mi respuesta para eliminar la información irrelevante.
Godric Seer
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.