Не всегда получайте ожидаемые результаты

Ниже приведен код простой модели приливно-отливного переноса, в которую я включил OpenMP для распараллеливания вычислений:

!$OMP PARALLEL SHARED(w, u, v, nthreads, chunk) PRIVATE(i, j, tid)
do it = 1, itlast
    !$OMP DO SCHEDULE(DYNAMIC, CHUNK)
    do j = 2, nyw-1
        do i = 2, nxw-1
            w(i,j) = w(i,j) - rx*depth*(u(i,j) - u(i-1,j))                  &
                            - ry*depth*(v(i,j) - v(i,j-1))
        end do
    end do
    !$OMP END DO
    !$OMP SINGLE
    call boudary_condition(it)
    !$OMP END SINGLE
    !$OMP DO SCHEDULE(DYNAMIC, CHUNK)
    do j = 1, nyw
        jv1 = j
        if (jv1 .ge. nyw-1) jv1 = nyw-1
        do i = 1, nxw-1
            u(i,j) = u(i,j) - rxg*(w(i+1,j) - w(i,j))                       &
                        - constant*u(i,j)*sqrt((u(i,j)**2.) + (v(i,jv1)**2.))
        end do
    end do
    !$OMP END DO
    !$OMP DO SCHEDULE(DYNAMIC, CHUNK)
    do j = 1, nyw-1
        do i = 1, nxw
            iu1 = i
            if (iu1 .ge. nxw-1) iu1 = nxw-1
            v(i,j) = v(i,j) - ryg*(w(i,j+1) - w(i,j))                       &
                        - constant*v(i,j)*sqrt((u(iu1,j)**2.) + (v(i,j)**2.))
        end do
    end do
    !$OMP END DO
    call transport_equation(chunk)
    !$OMP MASTER        
    mtprint = it/ntserprint
    if (ntserprint*mtprint .ne. it) goto 20
        call timeseries(it)
20  continue
    !$OMP END MASTER
end do
!$OMP END PARALLEL

Проблема в том, что я не всегда получаю ожидаемые результаты. Используя один и тот же входной файл, я всегда должен получать одинаковые результаты, но иногда в выходном файле получается NaN. Я не совсем понимаю, почему это происходит. Я использую Intel Visual Fortran Composer XE 2013 в Windows 10 для компиляции и запуска исполняемого файла.


person Wai Kiat    schedule 24.09.2015    source источник


Ответы (1)


Вам нужно как минимум иметь it, jv1 и ui1 закрытые. Попробуйте сначала исправить их и сообщите нам.

person Gilles    schedule 24.09.2015
comment
Привет @Gilles, спасибо за помощь. Я понимаю, почему iu1 и jv1 должны быть закрытыми, но я не совсем понимаю, почему в этом случае it также должен быть закрытым. it здесь итерация, т.е. временной шаг, а мой прилагаемый код не зависит от времени. - person Wai Kiat; 24.09.2015
comment
Я понимаю, что в Фортране директива SINGLE приказывает другим потокам ждать, пока выбранный поток не завершит выполнение кода в блоке !$OMP SINGLE. Разве директива MASTER не делает то же самое? Все потоки будут синхронизироваться в !$OMP END MASTER? - person Wai Kiat; 24.09.2015
comment
В целом, любая переменная, которая обновляется внутри области parallel, должна быть тщательно изучена. Здесь, поскольку it является счетчиком цикла для цикла, который явно не оформлен omp do, он должен быть объявлен private . В противном случае разные потоки будут обновлять его в совершенно случайном порядке и давать неопределенное поведение. - person Gilles; 24.09.2015
comment
single подразумевает barrier, но не определяет, какой поток будет выполнять раздел. master ограничивает раздел кода основным потоком, но не подразумевает никакого barrier при выходе. - person Gilles; 24.09.2015
comment
Привет @Gilles, спасибо за быстрый ответ. Я так понимаю, после того, как it, iu1 и jv1 оказались в предложении PRIVATE, а исполняемый файл был запущен 50 раз, модель до сих пор не выдавала NaN. Большое спасибо. - person Wai Kiat; 24.09.2015
comment
Хорошо, в этом случае мне нужно barrier. Я изменю это. Еще раз спасибо за вашу помощь. - person Wai Kiat; 24.09.2015
comment
На самом деле, все счетчики циклов являются частными автоматически, их не нужно явно определять как частные. В Fortran (в отличие от C) это, как ни странно, касается даже циклов, вложенных внутрь распараллеленного, поэтому даже i и j автоматически являются закрытыми. - person Vladimir F; 24.09.2015
comment
@VladimirF, вы правы, но только для конструкции anomp do. В этом случае it — это индексный счетчик цикла do, который находится внутри конструкции omp parallel, но вне какой-либо конструкции omp do. Таким образом, это не индекс общего цикла работы и не индекс цикла, вложенного в такой цикл. Итак, мое прочтение строк 7-9, раздела 2.7.1 p55 стандарта 4.0 позвольте мне подумать, что it не приватизирован по умолчанию... Я что-то пропустил или пропустил? - person Gilles; 25.09.2015
comment
Нет, вы правы, я пропустил, что петля it находится только в параллельной области. - person Vladimir F; 25.09.2015
comment
@VladimirF @Gilles Итак, в пункте PRIVATE мне как минимум нужно иметь it, iu1 и jv1, а i, j нельзя включать в пункт PRIVATE? Должен ли я поставить !$OMP BARRIER после !$OMP END MASTER и до end do цикла it do, чтобы обеспечить синхронизацию всех потоков перед переходом к следующей итерации? - person Wai Kiat; 25.09.2015
comment
Да, я так думаю. Тем не менее, я также настоятельно рекомендую вам сохранить как i, так и j в предложении private, даже если они уже неявно присутствуют там, поскольку это проясняет ситуацию. - person Gilles; 25.09.2015
comment
@Жиль Спасибо за совет. Я запомню это. Спасибо! - person Wai Kiat; 25.09.2015