#cuda #fortran #cufft
#cuda #fortran #cufft
Вопрос:
У меня возникли проблемы с использованием cufftPlanMany. После создания планов и принятия прямого и обратного БПФ я не смог вернуть исходные данные. Пожалуйста, найдите прилагаемую минимальную версию кода.
program test_cufft
use cudafor
use cufft
integer :: plan_r2c
integer :: plan_c2r
real,allocatable,dimension(:,:,:,:), device :: eta_d
complex,allocatable,dimension(:,:,:,:), device :: etak_d
nv = 4
nx = 256
ny = 512
nz = 512
nx21 = nx/2 1
allocate( eta_d(nv,nx,ny,nz) )
allocate( etak_d(nv,nx21,ny,nz) )
batch = nv;
rank = 3;
n = (/ nx, ny, nz /);
idist = nx*ny*nz;
odist = nx21*ny*nz;
inembed = (/ nx, ny, nz /);
onembed = (/ nx21, ny, nz /);
istride = 1;
ostride = 1;
istat = cufftPlanMany( plan_r2c, rank, n, inembed, istride, idist, amp;
onembed, ostride, odist, CUFFT_R2C, batch )
istat = cufftPlanMany( plan_c2r, rank, n, onembed, ostride, odist, amp;
inembed, istride, idist, CUFFT_C2R, batch )
! Initialize eta_d
istat = cufftExecR2C( plan_r2c, eta_d, etak_d )
istat = cufftExecC2R( plan_c2r, etak_d, eta_d )
eta_d = eta_d/idist
end program test_cufft
Проблема в том, что после того, как я выполнил прямое и обратное БПФ, я не смог вернуть исходные данные.
Пожалуйста, что я делаю не так?
Должен ли порядок данных быть eta_d(batch,nx,ny,nz) or eta_d(nx,ny,nz,batch)
?
Комментарии:
1. Такого рода прямое / обратное преобразование не вернет исходные данные обратно, если вы не масштабируете (не делите) конечные результаты на размер преобразования, т. е.
idist
. смотрите здесь .2. Это правильно, Роберт. Я разделил на
idist
. Я отредактировал вопрос, чтобы показать это. В чем я не уверен, так это в упорядоченииn, inembed, inembed
.
Ответ №1:
Я бы сказал, что правильный порядок (nz, ny, nx, batch)
Но важно также соотнести их с индексацией вашего массива и порядком хранения.
В терминологии CUFFT, для 3D-преобразования (*) nz
направление является наиболее быстро изменяющимся индексом, при этом типичное использование (шаг = 1) является смежными данными в памяти, соответствующими смежным элементам в преобразовании.
Это направление (я думаю о нем как об элементах вдоль строки, т. Е. Индекс «z» является индексом столбца) также является направлением многомерного преобразования, которое «уменьшается» в сложной области для типов преобразований R2C / C2R.
Имея это в виду, я бы переписал ваш код таким образом:
$ cat t4.cuf
program test_cufft
use cudafor
use cufft
integer :: plan_r2c
integer :: plan_c2r
real,allocatable,dimension(:,:,:,:), managed :: eta_d
complex,allocatable,dimension(:,:,:,:), managed :: etak_d
integer :: n(3), inembed(3), onembed(3),rank,istride,idist,ostride,odist,batch
nv = 4
nx = 8
ny = 8
nz = 4
nz21 = nz/2 1
allocate( eta_d(nz,ny,nx,nv) )
allocate( etak_d(nz21,ny,nx,nv) )
batch = nv;
rank = 3;
n = (/ nx, ny, nz /);
idist = nx*ny*nz;
odist = nx*ny*nz21;
inembed = (/ nx, ny, nz /);
onembed = (/ nx, ny, nz21 /);
istride = 1;
ostride = 1;
istat = cufftPlanMany( plan_r2c, rank, n, inembed, istride, idist, onembed, ostride, odist, CUFFT_R2C, batch )
istat = cufftPlanMany( plan_c2r, rank, n, onembed, ostride, odist, inembed, istride, idist, CUFFT_C2R, batch )
! Initialize eta_d
eta_d(:,:,:,:) = 1.0
eta_d(1,1,1,2) = 2.0
istat = cufftExecR2C( plan_r2c, eta_d, etak_d )
istat = cudaDeviceSynchronize()
eta_d(:,:,:,:) = 0.0
istat = cufftExecC2R( plan_c2r, etak_d, eta_d )
istat = cudaDeviceSynchronize()
eta_d = eta_d/idist
print *,eta_d(1,1,1,1)
print *,eta_d(1,1,1,2)
end program test_cufft
$ nvfortran t4.cuf -lcufft
$ ./a.out
1.000000
2.000000
$
(NVIDIA HPC SDK 20.9, графический процессор Tesla V100)
и, похоже, это дает ожидаемые результаты для моего простого тестового примера.
(*) Для 2D-преобразования ny
размерность будет наиболее быстро изменяться, а для одномерного преобразования nx
размерность (конечно) будет наиболее быстро изменяться.
Разделы многомерных преобразований и расширенной компоновки данных руководства CUFFT также могут быть полезны для чтения.
Комментарии:
1. Спасибо. Это работает нормально. Но терминология CUFFT предназначена для C. Поскольку массив fortran имеет порядок следования столбцов , самый левый нижний индекс изменяется наиболее быстро с шагом в единицу, для eta_d(batch, nx, ny, nz) это будет batch . Не могли бы вы прокомментировать это, пожалуйста?
2. Кроме того, я обнаружил, что следующие определения также работают нормально.
batch = nv; rank = 3; n = (/ nz, ny, nx /); idist = nz*ny*nx; odist = nz*ny*nx21; inembed = (/ nz, ny, nx /); onembed = (/ nz, ny, nx21 /); istride = 1; ostride = 1;
. С массивами, выделенными какallocate( eta_d(nv,nx,ny,nz) ); allocate( etak_d(nv,nx21,ny,nz) )
. И все остальное такое же, как в вашем решении. Можете ли вы прокомментировать это также?3. Да, вы правы, у меня были обратные порядки распределения измерений, я их поменял местами. в противном случае код остается неизменным. Что касается вашего второго комментария, я бы не стал уточнять
n
, посколькуn = (/ nz, ny, nx /);
для меня это просто не имеет смысла. Кроме того, просто для ясности, CUFFT ничего не интерпретирует в основном порядке строк или столбцов. Интерпретация размеров будет такой, как описано в руководстве CUFFT. Разделы, на которые я уже ссылался, явно указывают, как элементы будут выбираться для каждого аспекта многомерного преобразования, в зависимости от того, как эти элементы упорядочены в памяти.