CUFFT | не могу понять простой пример

Я боролся весь день, пытаясь заставить базовый пример CUFFT работать должным образом. Однако я сталкиваюсь с небольшой проблемой, которую не могу определить. В основном у меня есть линейный 2D массив vx с координатами x и y. Затем я просто вычисляю вперед, затем назад CUFFT (на месте), это просто. Затем я копирую обратно массив vx, нормализую его по NX * NY, затем отображаю.

#define NX 32
#define NY 32
#define LX (2*M_PI)
#define LY (2*M_PI)
float *x = new float[NX*NY];
float *y = new float[NX*NY];
float *vx = new float[NX*NY];
for(int j = 0; j < NY; j++){
    for(int i = 0; i < NX; i++){
        x[j*NX + i] = i * LX/NX;
        y[j*NX + i] = j * LY/NY;
        vx[j*NX + i] = cos(x[j*NX + i]);
    }
}
float *d_vx;
CUDA_CHECK(cudaMalloc(&d_vx, NX*NY*sizeof(float)));
CUDA_CHECK(cudaMemcpy(d_vx, vx, NX*NY*sizeof(float), cudaMemcpyHostToDevice));
cufftHandle planr2c;
cufftHandle planc2r;
CUFFT_CHECK(cufftPlan2d(&planr2c, NY, NX, CUFFT_R2C));
CUFFT_CHECK(cufftPlan2d(&planc2r, NY, NX, CUFFT_C2R));
CUFFT_CHECK(cufftSetCompatibilityMode(planr2c, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftSetCompatibilityMode(planc2r, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftExecR2C(planr2c, (cufftReal *)d_vx, (cufftComplex *)d_vx));
CUFFT_CHECK(cufftExecC2R(planc2r, (cufftComplex *)d_vx, (cufftReal *)d_vx));
CUDA_CHECK(cudaMemcpy(vx, d_vx, NX*NY*sizeof(cufftReal), cudaMemcpyDeviceToHost));
for (int j = 0; j < NY; j++){
    for (int i = 0; i < NX; i++){
        printf("%.3f ", vx[j*NX + i]/(NX*NY));
    }
    printf("\n");
}

Когда vx определяется как cos (x) или sin (x), он работает нормально, но при использовании sin (y) или cos (y) он возвращает мне правильную функцию (sin или cos), но с половиной амплитуды (что колеблется между 0,5 и -0,5 вместо 1 и -1)! Обратите внимание, что использование sin(2*y) или cos(2*y) (или sin(4*y), cos(4*y), ...) работает нормально. Любая идея?

1 ответ

Решение

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

cufftExecR2C () (cufftExecD2Z ()) выполняет план преобразования с преобразованием CUFFT с одинарной (двойной) точностью от реального к сложному, неявно вперед. CUFFT использует в качестве входных данных память GPU, указанную параметром idata. Эта функция хранит невосстановимые коэффициенты Фурье в массиве одат. Указатели на idata и odata должны быть приведены в соответствие с типом данных cufftComplex в преобразованиях одинарной точности и типом данных cufftDoubleComplex в преобразованиях двойной точности.

Решение состоит в том, чтобы либо выделить второй буфер устройства для хранения промежуточного результата, либо увеличить выделение на месте, чтобы он был достаточно большим для хранения сложных данных. Таким образом, код преобразования ядра изменяется на что-то вроде:

float *d_vx;
CUDA_CHECK(cudaMalloc(&d_vx, NX*NY*sizeof(cufftComplex)));
CUDA_CHECK(cudaMemcpy(d_vx, vx, NX*NY*sizeof(cufftComplex), cudaMemcpyHostToDevice));
cufftHandle planr2c;
cufftHandle planc2r;
CUFFT_CHECK(cufftPlan2d(&planr2c, NY, NX, CUFFT_R2C));
CUFFT_CHECK(cufftPlan2d(&planc2r, NY, NX, CUFFT_C2R));
CUFFT_CHECK(cufftSetCompatibilityMode(planr2c, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftSetCompatibilityMode(planc2r, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftExecR2C(planr2c, (cufftReal *)d_vx, d_vx));
CUFFT_CHECK(cufftExecC2R(planc2r, d_vx, (cufftReal *)d_vx));
CUDA_CHECK(cudaMemcpy(vx, d_vx, NX*NY*sizeof(cufftComplex), cudaMemcpyDeviceToHost));

[заявление об отказе: написано в браузере, никогда не компилируется и не тестируется, используйте на свой страх и риск]

Обратите внимание, что вам необходимо настроить код хоста в соответствии с размером и типом ввода и данных.

В качестве последнего комментария, было бы так сложно добавить дополнительные 8 или 10 строк, необходимых для превращения того, что вы опубликовали, в скомпилируемый, выполнимый пример, с которым кто-то пытается помочь вам работать?

Другие вопросы по тегам