2013-10-05 3 views
0

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

#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"); 
} 

Когда ъх определяется как соз (х) или грех (х), она работает нормально, но при использовании греха (у) или соз (у), это дает мне обратно правильную функцию (грех или соз), но с половинной амплитудой (т. е. осциллируя между 0,5 и -0,5 вместо 1 и -1)! Заметим, что использование sin (2 * y) или cos (2 * y) (или sin (4 * y), cos (4 * y), ...) отлично работает. Есть идеи?

+0

Почему ваша первая операция cudaMemcpy указывает cudaMemcpyDeviceToHost? Это не имеет смысла и не соответствует порядку указателей. Если ваш макрос CUDA_CHECK не вызывает ошибку, тогда что-то не так с вашим макросом. –

+0

Извините, я не копировал/вставлял правильную строку, в моем коде смысл копии правильный. Я обновляю –

+1

. Эта строка кода, которую вы ранее не могли быть в любом месте. Если эта строка кода отображается в другом месте вашего кода, это неверно. Кстати, SO ожидает, что вы предоставите код SSCCE.org для таких вопросов. –

ответ

4

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

cufftExecR2C() (cufftExecD2Z()) выполняет с одинарной точностью (двойной точности) в режиме реального к сложному, неявно вперед, CUFFT преобразования плана. CUFFT использует в качестве входных данных память GPU, на которую указывает параметр idata. Эта функция хранит ненужные коэффициенты Фурье в массиве odata. Указатели на 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 строк, необходимых для того, чтобы превратить то, что вы отправили, в компилируемый, исполняемый пример, с которым кто-то пытается помочь вам?

+0

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

+0

Для справок в будущем: Это неверно. Для преобразований R2C/C2R вам требуется примерно половина памяти сложного типа. У вас есть (NX/2 + 1) * NY комплексные элементы, которые являются (NX + 2) * NY действительными элементами для четных NX и (NX + 1) * NY реальных элементов для нечетных NX – Flamefire

Смежные вопросы