Day 67

GPU Kernels Learning Journey

Description

### Files: `poisson_solver.cu` Today I implemented a CUDA-accelerated Jacobi solver for the 2D Poisson equation. The goal was to solve ∇²u=f using a finite-difference scheme and iterative updates on a GPU.

Code Files

poisson_solver.cu

#include <iostream>
#include <cuda_runtime.h>

#define N 500  
#define BLOCK_SIZE 16  
#define TOLERANCE 1e-5 // Convergence threshold

__global__ void jacobi_kernel(double *u_new, double *u_old, double *f, int n, double h2) {
    int i = blockIdx.x * blockDim.x + threadIdx.x + 1;
    int j = blockIdx.y * blockDim.y + threadIdx.y + 1;
    
    if (i < n-1 && j < n-1) {
        int idx = j * n + i;
        u_new[idx] = 0.25 * (u_old[idx - 1] + u_old[idx + 1] + u_old[idx - n] + u_old[idx + n] - h2 * f[idx]);
    }
}

void solve_poisson(double *u, double *f, int n) {
    double *d_u_old, *d_u_new, *d_f;
    size_t size = n * n * sizeof(double);

    cudaMalloc(&d_u_old, size);
    cudaMalloc(&d_u_new, size);
    cudaMalloc(&d_f, size);

    cudaMemcpy(d_u_old, u, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_u_new, u, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_f, f, size, cudaMemcpyHostToDevice);

    dim3 threadsPerBlock(BLOCK_SIZE, BLOCK_SIZE);
    dim3 numBlocks((n + threadsPerBlock.x - 1) / threadsPerBlock.x,
                   (n + threadsPerBlock.y - 1) / threadsPerBlock.y);

    double h2 = 1.0 / (n * n);
    int maxIter = 10000;
    for (int iter = 0; iter < maxIter; iter++) {
        jacobi_kernel<<<numBlocks, threadsPerBlock>>>(d_u_new, d_u_old, d_f, n, h2);
        cudaMemcpy(d_u_old, d_u_new, size, cudaMemcpyDeviceToDevice);
    }

    cudaMemcpy(u, d_u_new, size, cudaMemcpyDeviceToHost);
    cudaFree(d_u_old);
    cudaFree(d_u_new);
    cudaFree(d_f);
}

int main() {
    double *u = new double[N * N]();
    double *f = new double[N * N]();

    // Set up the source term f(x,y)
    for (int j = 0; j < N; j++) {
        for (int i = 0; i < N; i++) {
            f[j * N + i] = sin(i * M_PI / N) * sin(j * M_PI / N);
        }
    }

    solve_poisson(u, f, N);
    
    for (int j = 0; j < N; j += N / 16) { 
        for (int i = 0; i < N; i += N / 16) {
            std::cout << u[j * N + i] << " ";
        }
        std::cout << std::endl;
    }
    
    delete[] u;
    delete[] f;
    return 0;
}