参考上述的建议,重新修改下面的代码:#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <fftw3.h>
// 结构体定义
typedef struct {
int iterations;
double time;
double energy;
double* phi;
} LBResult;
// 函数声明
double compute_energy(double* phi, fftw_complex* phi_fft, double* k2, int N, double tau, double gamma);
LBResult solve_LB_C2C(int N, double tau, double gamma, double dt, double tol, int maxiter);
LBResult solve_LB_C2R(int N, double tau, double gamma, double dt, double tol, int maxiter);
void cleanup_result(LBResult* result);
// 计算能量函数
double compute_energy(double* phi, fftw_complex* phi_fft, double* k2, int N, double tau, double gamma) {
// 分配内存
fftw_complex* A_phi_fft = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* A_phi_temp = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
double* A_phi = (double*)fftw_malloc(N * N * sizeof(double));
// 创建IFFT计划
fftw_plan plan_ifft = fftw_plan_dft_2d(N, N, A_phi_fft, A_phi_temp, FFTW_BACKWARD, FFTW_ESTIMATE);
// 计算 A_phi_fft = (1 - k2) .* phi_fft
for (int i = 0; i < N * N; i++) {
double factor = 1.0 - k2[i];
A_phi_fft[i][0] = factor * phi_fft[i][0];
A_phi_fft[i][1] = factor * phi_fft[i][1];
}
// A_phi = ifft2(A_phi_fft, 'symmetric') * N^2
fftw_execute(plan_ifft);
// 提取实部并归一化(对应MATLAB的 * N^2)
for (int i = 0; i < N * N; i++) {
A_phi[i] = A_phi_temp[i][0]; // FFTW的IFFT已经包含了正确的缩放
}
// 计算各项能量
double E1 = 0.0, E2 = 0.0, E3 = 0.0, E4 = 0.0;
for (int i = 0; i < N * N; i++) {
double A_phi_sq = A_phi[i] * A_phi[i];
double phi_sq = phi[i] * phi[i];
double phi_cu = phi[i] * phi[i] * phi[i];
double phi_qu = phi[i] * phi[i] * phi[i] * phi[i];
E1 += A_phi_sq;
E2 += phi_sq;
E3 += phi_cu;
E4 += phi_qu;
}
// 计算平均值(对应MATLAB的mean函数)
double norm = 1.0 / (N * N);
E1 = 0.5 * E1 * norm; // 0.5 * mean(A_phi_sq(:))
E2 = (tau / 2.0) * E2 * norm; // (tau/2) * mean(phi_sq(:))
E3 = (-gamma / 6.0) * E3 * norm; // (-gamma/6) * mean(phi_cu(:))
E4 = (1.0 / 24.0) * E4 * norm; // (1/24) * mean(phi_qu(:))
double energy = E1 + E2 + E3 + E4;
// 清理内存
fftw_destroy_plan(plan_ifft);
fftw_free(A_phi_fft);
fftw_free(A_phi_temp);
fftw_free(A_phi);
return energy;
}
// C2C方法求解
LBResult solve_LB_C2C(int N, double tau, double gamma, double dt, double tol, int maxiter) {
LBResult result;
clock_t start_time = clock();
// 分配内存
fftw_complex* phi_fft = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* phi_old_fft = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* phi_sq_fft = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* phi_cu_fft = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* phi_temp = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* phi_sq_temp = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
fftw_complex* phi_cu_temp = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
double* phi = (double*)fftw_malloc(N * N * sizeof(double));
double* phi_old = (double*)fftw_malloc(N * N * sizeof(double));
double* phi_sq = (double*)fftw_malloc(N * N * sizeof(double));
double* phi_cu = (double*)fftw_malloc(N * N * sizeof(double));
double* k2 = (double*)malloc(N * N * sizeof(double));
// 生成波数 - 严格按照MATLAB代码
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
double kx, ky;
// MATLAB: if i <= N/2, k(i) = i - 1; else k(i) = i - N - 1; end
if (i + 1 <= N / 2) { // MATLAB索引从1开始
kx = (double)i;
}
else {
kx = (double)(i - N);
}
if (j + 1 <= N / 2) {
ky = (double)j;
}
else {
ky = (double)(j - N);
}
k2[i * N + j] = kx * kx + ky * ky;
}
}
// 创建FFTW计划
fftw_plan plan_ifft = fftw_plan_dft_2d(N, N, phi_fft, phi_temp, FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_plan plan_fft_sq = fftw_plan_dft_2d(N, N, phi_sq_temp, phi_sq_fft, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_plan plan_fft_cu = fftw_plan_dft_2d(N, N, phi_cu_temp, phi_cu_fft, FFTW_FORWARD, FFTW_ESTIMATE);
// 初始化 phi_fft = zeros(N, N)
for (int i = 0; i < N * N; i++) {
phi_fft[i][0] = 0.0;
phi_fft[i][1] = 0.0;
}
// 设置初始条件
// MATLAB: phi_fft(2, 1) = 0.3; phi_fft(N, 1) = 0.3;
// 转换为C索引: (2,1) -> [1][0], (N,1) -> [N-1][0]
phi_fft[1 * N + 0][0] = 0.3; // phi_fft(2, 1) = 0.3
phi_fft[1 * N + 0][1] = 0.0;
phi_fft[(N - 1) * N + 0][0] = 0.3; // phi_fft(N, 1) = 0.3
phi_fft[(N - 1) * N + 0][1] = 0.0;
// 迭代求解
int iter;
for (iter = 0; iter < maxiter; iter++) {
// 保存旧值 phi_old_fft = phi_fft
for (int i = 0; i < N * N; i++) {
phi_old_fft[i][0] = phi_fft[i][0];
phi_old_fft[i][1] = phi_fft[i][1];
}
// phi_old = ifft2(phi_old_fft, 'symmetric') * N^2
fftw_execute(plan_ifft);
for (int i = 0; i < N * N; i++) {
phi_old[i] = phi_temp[i][0]; // 提取实部,FFTW已经正确缩放
}
// 计算非线性项
for (int i = 0; i < N * N; i++) {
phi_sq[i] = phi_old[i] * phi_old[i];
phi_cu[i] = phi_old[i] * phi_old[i] * phi_old[i];
// 准备复数数组用于FFT
phi_sq_temp[i][0] = phi_sq[i];
phi_sq_temp[i][1] = 0.0;
phi_cu_temp[i][0] = phi_cu[i];
phi_cu_temp[i][1] = 0.0;
}
// phi_sq_fft = fft2(phi_sq) / N^2
// phi_cu_fft = fft2(phi_cu) / N^2
fftw_execute(plan_fft_sq);
fftw_execute(plan_fft_cu);
// 归一化 (除以 N^2)
for (int i = 0; i < N * N; i++) {
phi_sq_fft[i][0] /= (N * N);
phi_sq_fft[i][1] /= (N * N);
phi_cu_fft[i][0] /= (N * N);
phi_cu_fft[i][1] /= (N * N);
}
// 更新
// numerator = (1 - dt*tau) * phi_old_fft + dt * (gamma/2 * phi_sq_fft - 1/6 * phi_cu_fft)
// denominator = 1 + dt*(1 - k2).^2
// phi_fft = numerator ./ denominator
for (int i = 0; i < N * N; i++) {
double k2_val = k2[i];
double numerator_real = (1.0 - dt * tau) * phi_old_fft[i][0] +
dt * (gamma / 2.0 * phi_sq_fft[i][0] - 1.0 / 6.0 * phi_cu_fft[i][0]);
double numerator_imag = (1.0 - dt * tau) * phi_old_fft[i][1] +
dt * (gamma / 2.0 * phi_sq_fft[i][1] - 1.0 / 6.0 * phi_cu_fft[i][1]);
double denominator = 1.0 + dt * pow(1.0 - k2_val, 2.0);
phi_fft[i][0] = numerator_real / denominator;
phi_fft[i][1] = numerator_imag / denominator;
}
// 保持零均值约束 phi_fft(1, 1) = 0
phi_fft[0][0] = 0.0;
phi_fft[0][1] = 0.0;
// 计算新的phi phi = ifft2(phi_fft, 'symmetric') * N^2
fftw_execute(plan_ifft);
for (int i = 0; i < N * N; i++) {
phi[i] = phi_temp[i][0];
}
// 检查收敛 diff = max(abs(phi(:) - phi_old(:))) / dt
double max_diff = 0.0;
for (int i = 0; i < N * N; i++) {
double diff = fabs(phi[i] - phi_old[i]) / dt;
if (diff > max_diff) {
max_diff = diff;
}
}
if (max_diff < tol) {
break;
}
}
clock_t end_time = clock();
double elapsed_time = ((double)(end_time - start_time)) / CLOCKS_PER_SEC;
// 计算能量
double energy = compute_energy(phi, phi_fft, k2, N, tau, gamma);
// 设置结果
result.iterations = iter + 1;
result.time = elapsed_time;
result.energy = energy;
result.phi = (double*)malloc(N * N * sizeof(double));
for (int i = 0; i < N * N; i++) {
result.phi[i] = phi[i];
}
// 清理内存
fftw_destroy_plan(plan_ifft);
fftw_destroy_plan(plan_fft_sq);
fftw_destroy_plan(plan_fft_cu);
fftw_free(phi_fft);
fftw_free(phi_old_fft);
fftw_free(phi_sq_fft);
fftw_free(phi_cu_fft);
fftw_free(phi_temp);
fftw_free(phi_sq_temp);
fftw_free(phi_cu_temp);
fftw_free(phi);
fftw_free(phi_old);
fftw_free(phi_sq);
fftw_free(phi_cu);
free(k2);
return result;
}
// C2R方法求解 - 修正后的版本
LBResult solve_LB_C2R(int N, double tau, double gamma, double dt, double tol, int maxiter) {
LBResult result;
clock_t start_time = clock();
// C2R变换的输出大小
int fft_size = N * (N / 2 + 1);
// 分配内存
fftw_complex* phi_fft = (fftw_complex*)fftw_malloc(fft_size * sizeof(fftw_complex));
fftw_complex* phi_old_fft = (fftw_complex*)fftw_malloc(fft_size * sizeof(fftw_complex));
fftw_complex* phi_sq_fft = (fftw_complex*)fftw_malloc(fft_size * sizeof(fftw_complex));
fftw_complex* phi_cu_fft = (fftw_complex*)fftw_malloc(fft_size * sizeof(fftw_complex));
double* phi = (double*)fftw_malloc(N * N * sizeof(double));
double* phi_old = (double*)fftw_malloc(N * N * sizeof(double));
double* phi_sq = (double*)fftw_malloc(N * N * sizeof(double));
double* phi_cu = (double*)fftw_malloc(N * N * sizeof(double));
double* k2 = (double*)malloc(fft_size * sizeof(double));
// 生成波数(C2R格式)
for (int i = 0; i < N; i++) {
for (int j = 0; j <= N / 2; j++) {
double kx, ky;
if (i + 1 <= N / 2) {
kx = (double)i;
}
else {
kx = (double)(i - N);
}
ky = (double)j;
k2[i * (N / 2 + 1) + j] = kx * kx + ky * ky;
}
}
// 创建FFTW计划
fftw_plan plan_c2r = fftw_plan_dft_c2r_2d(N, N, phi_fft, phi, FFTW_ESTIMATE);
fftw_plan plan_r2c_sq = fftw_plan_dft_r2c_2d(N, N, phi_sq, phi_sq_fft, FFTW_ESTIMATE);
fftw_plan plan_r2c_cu = fftw_plan_dft_r2c_2d(N, N, phi_cu, phi_cu_fft, FFTW_ESTIMATE);
// 初始化
for (int i = 0; i < fft_size; i++) {
phi_fft[i][0] = 0.0;
phi_fft[i][1] = 0.0;
}
// 设置初始条件 - 修正版本
// 原来的C2C初始条件:phi_fft(2, 1) = 0.3; phi_fft(N, 1) = 0.3;
// 对应波数 k = (1, 0) 和 k = (-1, 0)
// 在C2R格式中:
// k = (1, 0) 对应 phi_fft[1 * (N/2 + 1) + 0] = 0.3
// k = (-1, 0) 由于共轭对称性,需要特殊处理
// 设置 k = (1, 0) 对应的值
phi_fft[1 * (N / 2 + 1) + 0][0] = 0.3;
phi_fft[1 * (N / 2 + 1) + 0][1] = 0.0;
// 设置 k = (-1, 0) 对应的值
// 在C2R中,负频率通过共轭对称性隐含表示
// k = (-1, 0) 对应 phi_fft[(N-1) * (N/2 + 1) + 0] = 0.3
phi_fft[(N - 1) * (N / 2 + 1) + 0][0] = 0.3;
phi_fft[(N - 1) * (N / 2 + 1) + 0][1] = 0.0;
// 迭代求解
int iter;
for (iter = 0; iter < maxiter; iter++) {
// 保存旧值
for (int i = 0; i < fft_size; i++) {
phi_old_fft[i][0] = phi_fft[i][0];
phi_old_fft[i][1] = phi_fft[i][1];
}
// 执行逆FFT到实空间
fftw_execute(plan_c2r);
// FFTW的C2R变换不归一化,需要手动归一化
for (int i = 0; i < N * N; i++) {
phi_old[i] = phi[i] / (N * N);
}
// 计算非线性项
for (int i = 0; i < N * N; i++) {
phi_sq[i] = phi_old[i] * phi_old[i];
phi_cu[i] = phi_old[i] * phi_old[i] * phi_old[i];
}
// 将非线性项FFT到频域
fftw_execute(plan_r2c_sq);
fftw_execute(plan_r2c_cu);
// 注意:FFTW的R2C变换不归一化,所以结果已经是正确的
// 更新频域值
for (int i = 0; i < fft_size; i++) {
double k2_val = k2[i];
double numerator_real = (1.0 - dt * tau) * phi_old_fft[i][0] +
dt * (gamma / 2.0 * phi_sq_fft[i][0] - 1.0 / 6.0 * phi_cu_fft[i][0]);
double numerator_imag = (1.0 - dt * tau) * phi_old_fft[i][1] +
dt * (gamma / 2.0 * phi_sq_fft[i][1] - 1.0 / 6.0 * phi_cu_fft[i][1]);
double denominator = 1.0 + dt * pow(1.0 - k2_val, 2.0);
phi_fft[i][0] = numerator_real / denominator;
phi_fft[i][1] = numerator_imag / denominator;
}
// 保持零均值约束
phi_fft[0][0] = 0.0;
phi_fft[0][1] = 0.0;
// 计算新的phi用于收敛检查
fftw_execute(plan_c2r);
// 归一化
for (int i = 0; i < N * N; i++) {
phi[i] = phi[i] / (N * N);
}
// 检查收敛
double max_diff = 0.0;
for (int i = 0; i < N * N; i++) {
double diff = fabs(phi[i] - phi_old[i]) / dt;
if (diff > max_diff) {
max_diff = diff;
}
}
if (max_diff < tol) {
break;
}
}
clock_t end_time = clock();
double elapsed_time = ((double)(end_time - start_time)) / CLOCKS_PER_SEC;
// 为了计算能量,需要将C2R结果转换为完整的C2C格式
fftw_complex* phi_fft_full = (fftw_complex*)fftw_malloc(N * N * sizeof(fftw_complex));
double* k2_full = (double*)malloc(N * N * sizeof(double));
// 展开C2R结果到完整格式 - 修正版本
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
double kx, ky;
if (i + 1 <= N / 2) kx = (double)i; else kx = (double)(i - N);
if (j + 1 <= N / 2) ky = (double)j; else ky = (double)(j - N);
k2_full[i * N + j] = kx * kx + ky * ky;
if (j <= N / 2) {
// 直接复制
int idx = i * (N / 2 + 1) + j;
phi_fft_full[i * N + j][0] = phi_fft[idx][0];
phi_fft_full[i * N + j][1] = phi_fft[idx][1];
}
else {
// 利用共轭对称性:F[i][N-j] = conj(F[N-i][j])
int i_sym = (i == 0) ? 0 : (N - i);
int j_sym = N - j;
int idx = i_sym * (N / 2 + 1) + j_sym;
phi_fft_full[i * N + j][0] = phi_fft[idx][0];
phi_fft_full[i * N + j][1] = -phi_fft[idx][1];
}
}
}
double energy = compute_energy(phi, phi_fft_full, k2_full, N, tau, gamma);
// 设置结果
result.iterations = iter + 1;
result.time = elapsed_time;
result.energy = energy;
result.phi = (double*)malloc(N * N * sizeof(double));
for (int i = 0; i < N * N; i++) {
result.phi[i] = phi[i];
}
// 清理内存
fftw_destroy_plan(plan_c2r);
fftw_destroy_plan(plan_r2c_sq);
fftw_destroy_plan(plan_r2c_cu);
fftw_free(phi_fft);
fftw_free(phi_old_fft);
fftw_free(phi_sq_fft);
fftw_free(phi_cu_fft);
fftw_free(phi);
fftw_free(phi_old);
fftw_free(phi_sq);
fftw_free(phi_cu);
fftw_free(phi_fft_full);
free(k2);
free(k2_full);
return result;
}
// 清理结果内存
void cleanup_result(LBResult* result) {
if (result->phi) {
free(result->phi);
result->phi = NULL;
}
}
// 主函数
int main() {
// 参数设置
double tau = -0.2;
double gamma = 0.1;
double dt = 0.1;
double tol = 1e-6;
int maxiter = 10000;
// 测试不同的网格尺寸
int N_values[] = { 4, 8, 16, 32, 64, 128, 256 };
int num_N = sizeof(N_values) / sizeof(N_values[0]);
printf("使用 C2C 方式计算:\n");
printf("N\t迭代次数\t时间 (s)\t能量\n");
for (int idx = 0; idx < num_N; idx++) {
int N = N_values[idx];
LBResult result = solve_LB_C2C(N, tau, gamma, dt, tol, maxiter);
printf("%d\t%d\t\t%.6f\t%.6e\n",
N, result.iterations, result.time, result.energy);
cleanup_result(&result);
}
printf("\n使用 C2R 方式计算:\n");
printf("N\t迭代次数\t时间 (s)\t能量\n");
for (int idx = 0; idx < num_N; idx++) {
int N = N_values[idx];
LBResult result = solve_LB_C2R(N, tau, gamma, dt, tol, maxiter);
printf("%d\t%d\t\t%.6f\t%.6e\n",
N, result.iterations, result.time, result.energy);
cleanup_result(&result);
}
return 0;
}