274 lines
7.5 KiB
Plaintext
274 lines
7.5 KiB
Plaintext
/**
|
|
* CUDA kernels for diffusion equation
|
|
*
|
|
* Implements various schemes for the diffusion/heat equation:
|
|
* ∂T/∂t = α∇²T
|
|
*
|
|
* Includes explicit, implicit, and Crank-Nicolson schemes.
|
|
*/
|
|
|
|
extern "C" __global__ void diffusion_explicit_1d(
|
|
const float* __restrict__ temp,
|
|
float* __restrict__ temp_new,
|
|
float alpha,
|
|
float dt,
|
|
float dx,
|
|
int n
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
|
|
if (i >= n) return;
|
|
|
|
float r = alpha * dt / (dx * dx); // Diffusion number
|
|
|
|
// Stability condition: r <= 0.5 for explicit scheme
|
|
if (r > 0.5f) {
|
|
// Issue warning - this should be handled at higher level
|
|
return;
|
|
}
|
|
|
|
// Boundary conditions (Dirichlet for now)
|
|
if (i == 0 || i == n - 1) {
|
|
temp_new[i] = temp[i]; // Fixed boundary values
|
|
return;
|
|
}
|
|
|
|
// Explicit finite difference: T_i^{n+1} = T_i^n + r(T_{i+1}^n - 2T_i^n + T_{i-1}^n)
|
|
temp_new[i] = temp[i] + r * (temp[i + 1] - 2.0f * temp[i] + temp[i - 1]);
|
|
}
|
|
|
|
extern "C" __global__ void diffusion_explicit_2d(
|
|
const float* __restrict__ temp,
|
|
float* __restrict__ temp_new,
|
|
float alpha,
|
|
float dt,
|
|
float dx,
|
|
float dy,
|
|
int nx,
|
|
int ny
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
|
|
if (i >= nx || j >= ny) return;
|
|
|
|
int idx = j * nx + i;
|
|
|
|
float rx = alpha * dt / (dx * dx);
|
|
float ry = alpha * dt / (dy * dy);
|
|
|
|
// Stability condition: rx + ry <= 0.5 for 2D explicit scheme
|
|
if (rx + ry > 0.5f) {
|
|
return;
|
|
}
|
|
|
|
// Boundary conditions
|
|
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
|
temp_new[idx] = temp[idx]; // Fixed boundary values
|
|
return;
|
|
}
|
|
|
|
int idx_ip1 = j * nx + (i + 1);
|
|
int idx_im1 = j * nx + (i - 1);
|
|
int idx_jp1 = (j + 1) * nx + i;
|
|
int idx_jm1 = (j - 1) * nx + i;
|
|
|
|
// 2D explicit finite difference
|
|
temp_new[idx] = temp[idx] +
|
|
rx * (temp[idx_ip1] - 2.0f * temp[idx] + temp[idx_im1]) +
|
|
ry * (temp[idx_jp1] - 2.0f * temp[idx] + temp[idx_jm1]);
|
|
}
|
|
|
|
extern "C" __global__ void diffusion_implicit_1d(
|
|
const float* __restrict__ temp,
|
|
float* __restrict__ temp_new,
|
|
float alpha,
|
|
float dt,
|
|
float dx,
|
|
int n
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
|
|
if (i >= n) return;
|
|
|
|
// For implicit scheme, this kernel performs one iteration of iterative solver
|
|
// (e.g., Jacobi iteration for the linear system)
|
|
|
|
float r = alpha * dt / (dx * dx);
|
|
|
|
// Boundary conditions
|
|
if (i == 0 || i == n - 1) {
|
|
temp_new[i] = temp[i];
|
|
return;
|
|
}
|
|
|
|
// Jacobi iteration for implicit scheme:
|
|
// (1 + 2r)T_i^{n+1} - r(T_{i+1}^{n+1} + T_{i-1}^{n+1}) = T_i^n
|
|
// T_i^{n+1} = (T_i^n + r(T_{i+1}^{n+1} + T_{i-1}^{n+1})) / (1 + 2r)
|
|
|
|
temp_new[i] = (temp[i] + r * (temp_new[i + 1] + temp_new[i - 1])) / (1.0f + 2.0f * r);
|
|
}
|
|
|
|
extern "C" __global__ void diffusion_crank_nicolson_1d(
|
|
const float* __restrict__ temp,
|
|
float* __restrict__ temp_new,
|
|
float alpha,
|
|
float dt,
|
|
float dx,
|
|
int n
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
|
|
if (i >= n) return;
|
|
|
|
float r = alpha * dt / (dx * dx);
|
|
|
|
// Boundary conditions
|
|
if (i == 0 || i == n - 1) {
|
|
temp_new[i] = temp[i];
|
|
return;
|
|
}
|
|
|
|
// Crank-Nicolson scheme (θ = 0.5):
|
|
// T_i^{n+1} - 0.5*r*(T_{i+1}^{n+1} - 2*T_i^{n+1} + T_{i-1}^{n+1}) =
|
|
// T_i^n + 0.5*r*(T_{i+1}^n - 2*T_i^n + T_{i-1}^n)
|
|
|
|
float rhs = temp[i] + 0.5f * r * (temp[i + 1] - 2.0f * temp[i] + temp[i - 1]);
|
|
|
|
// Jacobi iteration for Crank-Nicolson
|
|
temp_new[i] = (rhs + 0.5f * r * (temp_new[i + 1] + temp_new[i - 1])) / (1.0f + r);
|
|
}
|
|
|
|
// Helper kernel for tridiagonal solver (Thomas algorithm)
|
|
extern "C" __global__ void thomas_forward_elimination(
|
|
float* __restrict__ a, // Lower diagonal
|
|
float* __restrict__ b, // Main diagonal
|
|
float* __restrict__ c, // Upper diagonal
|
|
float* __restrict__ d, // Right hand side
|
|
int n
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x + 1; // Start from i=1
|
|
|
|
if (i >= n) return;
|
|
|
|
// Forward elimination step
|
|
float m = a[i] / b[i - 1];
|
|
b[i] = b[i] - m * c[i - 1];
|
|
d[i] = d[i] - m * d[i - 1];
|
|
}
|
|
|
|
extern "C" __global__ void thomas_backward_substitution(
|
|
const float* __restrict__ b, // Modified main diagonal
|
|
const float* __restrict__ c, // Upper diagonal
|
|
float* __restrict__ d, // Modified RHS / solution
|
|
int n
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
|
|
if (i >= n - 1) return; // n-2, n-3, ..., 0
|
|
|
|
int idx = n - 2 - i; // Reverse order
|
|
|
|
if (idx < n - 1) {
|
|
d[idx] = (d[idx] - c[idx] * d[idx + 1]) / b[idx];
|
|
}
|
|
}
|
|
|
|
// Advanced diffusion kernels with anisotropic diffusion
|
|
extern "C" __global__ void anisotropic_diffusion_2d(
|
|
const float* __restrict__ temp,
|
|
float* __restrict__ temp_new,
|
|
const float* __restrict__ kappa_x, // Diffusivity in x-direction
|
|
const float* __restrict__ kappa_y, // Diffusivity in y-direction
|
|
float dt,
|
|
float dx,
|
|
float dy,
|
|
int nx,
|
|
int ny
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
|
|
if (i >= nx || j >= ny) return;
|
|
|
|
int idx = j * nx + i;
|
|
|
|
// Boundary conditions
|
|
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
|
temp_new[idx] = temp[idx];
|
|
return;
|
|
}
|
|
|
|
int idx_ip1 = j * nx + (i + 1);
|
|
int idx_im1 = j * nx + (i - 1);
|
|
int idx_jp1 = (j + 1) * nx + i;
|
|
int idx_jm1 = (j - 1) * nx + i;
|
|
|
|
// Anisotropic diffusion with spatially varying diffusivity
|
|
float kx = kappa_x[idx];
|
|
float ky = kappa_y[idx];
|
|
|
|
float rx = kx * dt / (dx * dx);
|
|
float ry = ky * dt / (dy * dy);
|
|
|
|
// Check stability condition
|
|
if (rx + ry > 0.5f) {
|
|
temp_new[idx] = temp[idx]; // Skip update if unstable
|
|
return;
|
|
}
|
|
|
|
temp_new[idx] = temp[idx] +
|
|
rx * (temp[idx_ip1] - 2.0f * temp[idx] + temp[idx_im1]) +
|
|
ry * (temp[idx_jp1] - 2.0f * temp[idx] + temp[idx_jm1]);
|
|
}
|
|
|
|
// Kernel for nonlinear diffusion (e.g., for turbulent heat transfer)
|
|
extern "C" __global__ void nonlinear_diffusion_2d(
|
|
const float* __restrict__ temp,
|
|
float* __restrict__ temp_new,
|
|
float base_alpha,
|
|
float dt,
|
|
float dx,
|
|
float dy,
|
|
int nx,
|
|
int ny
|
|
) {
|
|
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
|
|
if (i >= nx || j >= ny) return;
|
|
|
|
int idx = j * nx + i;
|
|
|
|
// Boundary conditions
|
|
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
|
temp_new[idx] = temp[idx];
|
|
return;
|
|
}
|
|
|
|
int idx_ip1 = j * nx + (i + 1);
|
|
int idx_im1 = j * nx + (i - 1);
|
|
int idx_jp1 = (j + 1) * nx + i;
|
|
int idx_jm1 = (j - 1) * nx + i;
|
|
|
|
// Compute local gradient magnitude
|
|
float grad_x = (temp[idx_ip1] - temp[idx_im1]) / (2.0f * dx);
|
|
float grad_y = (temp[idx_jp1] - temp[idx_jm1]) / (2.0f * dy);
|
|
float grad_mag = sqrtf(grad_x * grad_x + grad_y * grad_y);
|
|
|
|
// Nonlinear diffusivity (example: edge-preserving diffusion)
|
|
float alpha = base_alpha / (1.0f + grad_mag * grad_mag);
|
|
|
|
float rx = alpha * dt / (dx * dx);
|
|
float ry = alpha * dt / (dy * dy);
|
|
|
|
// Check stability
|
|
if (rx + ry > 0.5f) {
|
|
temp_new[idx] = temp[idx];
|
|
return;
|
|
}
|
|
|
|
temp_new[idx] = temp[idx] +
|
|
rx * (temp[idx_ip1] - 2.0f * temp[idx] + temp[idx_im1]) +
|
|
ry * (temp[idx_jp1] - 2.0f * temp[idx] + temp[idx_jm1]);
|
|
} |