Эффективная проверка сходимости - PullRequest
1 голос
/ 17 декабря 2010

У меня есть сетка с тысячами вещественных чисел двойной точности.

Она проходит через все, и мне нужно ее остановить, когда она достигнет сходимости до 3 десятичных знаков.он работает максимально быстро, но каждый раз должен давать один и тот же результат (до 3 dp).

В тот момент, когда я делаю что-то вроде этого

REAL(KIND=DP) :: TOL = 0.001_DP

DO WHILE(.NOT. CONVERGED)
    CONVERGED = .TRUE.
    DO I = 1, NUM_POINTS
        NEW POTENTIAL = !blah blah blah
        IF (CONVERGED) THEN
            IF (NEW_POTENTIAL < OLD_POTENTIAL - TOL .OR. NEW_POTENTIAL > OLD_POTENTIAL + TOL) THEN
                CONVERGED = .FALSE.
            END IF
        END IF
        OLD_POTENTIAL = NEW POTENTIAL
    END DO  
END DO

I 'Я думаю, что многие заявления IF не могут быть слишком хорошими для производительности.Я думал о проверке сходимости в конце;найти среднее значение (суммируя всю сетку, разделив на num_points) и проверив, сходилось ли оно так же, как и выше, но я не уверен, что это всегда будет точно.

Что лучшеспособ сделать это?

Ответы [ 3 ]

3 голосов
/ 17 декабря 2010

Если я правильно понимаю, у вас происходит какое-то пошаговое изменение времени, когда вы создаете значения в new_potential путем вычислений на old_potential.Затем сделайте старое равным новому и продолжайте.

Вы можете заменить существующие тесты сходимости одним оператором

converged = all(abs(new_potential - old_potential)<tol)

, который может быть быстрее.Если скорость теста является серьезной проблемой, вы можете проверить только каждую другую (или каждую третью или четвертую ...) итерацию

Несколько комментариев:

1) Если вы использовали потенциальныймассив с двумя плоскостями, вместо old_ и new_potential, вы можете перевести new_ в old_, поменяв местами индексы в конце каждой итерации.Поскольку ваш код стоит, происходит много движения данных.

2) Хотя с семантической точки зрения вы и вправе иметь цикл while, я бы всегда использовал цикл do с максимальным числом итераций, на всякий случайкритерий сходимости никогда не выполняется.

3) В вашей декларации REAL(KIND=DP) :: TOL = 0.001_DP спецификация DP для числового значения TOL является избыточной, REAL(KIND=DP) :: TOL = 0.001 является адекватным.Я бы также сделал это параметром, компилятор может оптимизировать его использование, если он знает, что он неизменен.

4) Вам действительно не нужно выполнять CONVERGED = .TRUE. внутри самого внешнего цикла,установите его перед первой итерацией - это сэкономит вам наносекунду или две.

Наконец, если ваш критерий сходимости состоит в том, что каждый элемент в потенциальном массиве сходится к 3dp, то это то, что вы должны проверить.Было бы относительно легко построить контрпримеры для предложенных вами средних значений.Однако меня беспокоит то, что ваша система никогда не будет сходиться на каждом элементе, и что вы должны использовать некоторое матричное вычисление нормы для определения сходимости.ТАК не место для урока в этой теме.

0 голосов
/ 03 марта 2011
I = 1
DO
  NEWPOT = !bla bla bla
  IF (ABS(NEWPOT-OLDPOT).LT.TOL) EXIT
  OLDPOT = NEWPOT
  I = MOD(I,NUMPOINTS) + 1
END DO

Может лучше

I = 1
DO
  NEWPOT = !bla bla bla
  IF (ABS(NEWPOT-OLDPOT).LT.TOL) EXIT
  OLDPOT = NEWPOT
  IF (I.EQ.NUMPOINTS) THEN
    I = 1
  ELSE
    I = I + 1
  END IF
END DO
0 голосов
/ 17 декабря 2010

Какие расчеты по критериям сходимости?Если они не хуже вычислений для повышения потенциала, вероятно, лучше иметь оператор IF, чтобы завершить цикл как можно скорее, а не угадывать очень большое количество итераций, чтобы быть уверенным в получении хорошего решения.

Re High Mark Mark предлагает # 1, если операция копирования составляет значительную часть времени выполнения, вы также можете использовать указатели.

Единственный способ убедиться в этом - это измерить время выполнения... Fortran предоставляет встроенные функции для измерения времени процессора и часов.В противном случае вы можете изменить некоторую часть своего кода, чтобы сделать его быстрее, возможно, сделать его менее понятным и, возможно, внести ошибку, возможно, без значительного улучшения во время выполнения ... если эта часть занимала небольшое количество общего времени выполнения,никакая хитрость не будет иметь большого значения.

Как говорит Марк Высокой производительности, хотя текущая семантика элегантна, вы, вероятно, захотите защититься от бесконечного цикла.Один подход:

PotentialLoop: do i=1, MaxIter

  blah

  Converged = test...
  if (Converged) exit PotentialLoop

  blah

end do PotentialLoop

if (.NOT. Converged) write (*, *) "error, did not converge"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...