Явний метод Ейлера занадто повільний для проблеми дифузії реакцій


10

Я вирішую систему реакції дифузії Тьюрінга з наступним кодом С ++. Це занадто повільно: для текстури розміром 128x128 пікселів прийнятна кількість ітерацій становить 200 - це призводить до затримки в 2,5 секунди. Мені потрібно 400 ітерацій, щоб отримати цікаве зображення - але 5 секунд очікування - це занадто багато. Також розмір текстури повинен бути насправді 512x512 - але це призводить до величезного часу очікування. Пристрої iPad, iPod.

Чи є шанс зробити це швидше? Метод Ейлера зближується повільно (wikipedia) - швидший метод дозволив би скинути кількість ітерацій?

EDIT: Як вказував Томас Клімпель, рядки: "if (m_An [i] [j] <0.0) {...}", "if (m_Bn [i] [j] <0.0) {...}" затримують конвергенцію: після видалення змістовне зображення з’являється після 75 ітерацій . Я прокоментував рядки в коді нижче.

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

Також хочу зазначити, що бажано не перепитувати запитання, оскільки, здається, ви задавали дуже схожі питання і тут, і тут .
Годрік Провид

Ви вже випадково бачили роботу Грега Турка про це?
JM

@JM: Ще не. Я просто спробував запустити його код: для нього потрібен X-сервер з PseudoColor, тобто 8-бітна глибина кольору. Я думаю, що я не можу забезпечити це на OSX. Я пробував різні сервери VNC, але не пощастило.
AllCoder

Я думаю, ви все-таки зможете адаптувати підхід Турка до цієї справи; Моделі реакції дифузії реакцій в даний час досить часто використовуються в комп'ютерній графіці.
JM

1
Я можу помилятися, але частина з m_An [i] [j] = 0,0; може фактично додати елемент до цієї системи, який неможливо змоделювати за допомогою диференціального рівняння з безперервним правою стороною. Це робить трохи складніше придумати швидший вирішувач.
Томас Клімпель

Відповіді:


9

Ви, здається, обмежені стабільністю, що очікується, оскільки дифузія жорстка під час вдосконалення сітки. Хороші методи жорстких систем принаймні частково неявні. Це займе певних зусиль, але ви можете реалізувати простий алгоритм з багаторешіткою (або використовувати бібліотеку) для вирішення цієї системи вартістю менше десяти "робочих одиниць" (по суті, вартості одного з ваших часових кроків). Коли ви доопрацюєте сітку, кількість повторень не збільшиться.


Якби тут була тільки жорстка дифузія, він міг би використовувати такий метод АДІ, як Дуглас-Ганн, і все було б добре. Однак, на моєму власному досвіді, реакційна частина часто набагато гірша щодо жорсткості, крім того, що вона є нелінійною.
Томас Клімпель

1
На жаль, ADI має жахливу пам'ять. Також зауважте, що реакцію можна розглядати неявно незалежно від того, чи є дифузія. За умови уточнення сітки дифузія з часом стане домінуючою, але ми не можемо сказати, де знаходиться поріг, не знаючи констант.
Джед Браун

Приклад коду, що реалізує відсталий Ейлер для цього (на Python), знаходиться тут: scicomp.stackexchange.com/a/2247/123
Девід Кетчесон

@DavidKetcheson: Використання неявних методів вимагає вирішення рівняння? Ось чому в коді є linalg.spsolve ()?
AllCoder

1
@AllCoder Так, це вимагає вирішення, але рішення можна зробити набагато швидше, ніж усі кроки часу, необхідні для явного методу, щоб бути стабільним.
Джед Браун

2

З практичної точки зору: процесор A5 не настільки потужний, тому ви можете зачекати кілька ітерацій HW, або якщо ваш ipod / ipad буде підключений до Інтернету, вирішити свою проблему віддалено або в хмарі.


Я здивований тим, як мала потужність пропонує A5. Як можуть так добре працювати Pages, Safari та інші великі програми? Мені потрібно генерувати випадкові, абстрактні зображення, думав, що морфогенез буде досить простим ..
AllCoder

Ну, A5 - це енергоефективний процесор, оптимізований для Інтернету та відео (Pages, Safari тощо). Навпаки, більшість числових навантажень виконують тонни операцій з плаваючою комою та переміщення даних, ці особливості не є увагою мобільних процесорів малої потужності.
fcruz

0

Ейлер поступово сходить по відношенню до інших методів, однак я не думаю, що саме це вас цікавить. Якщо ви просто шукаєте "цікаві" зображення, збільште розмір свого кроку в часі і робіть менше ітерацій. Проблема, як вказує Джед, полягає в тому, що метод явного еулера має проблеми зі стабільністю з великими часовими кроками щодо розміру сітки. чим менша ваша сітка (тобто чим вище роздільна здатність вашого зображення), тим меншим повинен бути ваш крок часу, щоб врахувати її.

Наприклад, використовуючи неявний ейлер замість явного, ви не отримуєте жодних порядків конвергенції, але рішення матиме безумовну стабільність, що дозволяє набагато більші часові кроки. Неявні методи складніші для впровадження та проведення більших обчислень за часовий крок, але ви повинні побачити вигоди набагато більше, ніж зробивши менше загальних кроків.


Ця проблема обмежена стабільністю, тому просто збільшити розмір кроку часу не вийде.
Джед Браун

Якщо я зміню 0,01 до 0,015, то я отримую "концентрацію хімічних сполук біля нуля" у всіх точках - тобто сірий квадрат. Ось походження мого коду: drdobbs.com/article/print?articleId=184410024
AllCoder

Так, це було б наслідком питань стабільності, про які згадував Джед. Як він зазначає у своїй відповіді, використання неявного методу, який характеризується кращими показниками стабільності, вирішить це питання для вас. Я оновлю свою відповідь, щоб видалити невідповідну інформацію.
Годрік Сір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.