#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define NX 100 // Number of spatial points
#define NT_TOTAL 500 // Total time steps for T = 0.5
#define X_MAX 1.0 // Maximum x value
#define PI 3.141592653589793
// Function prototypes
double erf_sol(double x, double t, double Re);
void explicit_scheme(double *u, double Re, int Nt, double dt, double dx);
void crank_nicolson_scheme(double *u, double Re, int Nt, double dt, double dx);
// Main function
int main() {
double x[NX], u_initial[NX];
double T_values[] = {0.36, 0.47}; // Times to evaluate the solution
double Re_values[] = {10, 50}; // Reynolds numbers
double u_exact[NX], u_explicit[NX], u_cn[NX];
double dt = 0.5 / NT_TOTAL; // Time step size
double dx = 2 * X_MAX / (NX - 1); // Spatial step size
// Generate grid and initialize conditions
for (int i = 0; i < NX; ++i) {
x[i] = -X_MAX + i * dx;
u_initial[i] = (x[i] < 0) ? 1.0 : 0.0; // Initial condition
}
// Open gnuplot
FILE *gp = popen("gnuplot -persistent", "w");
fprintf(gp
, "set multiplot layout 2,2\n");
for (int r = 0; r < 2; ++r) {
double Re = Re_values[r];
for (int t_idx = 0; t_idx < 2; ++t_idx) {
double T = T_values[t_idx];
int Nt = (int)(T / dt); // Number of time steps
// Exact solution
for (int i = 0; i < NX; ++i) {
u_exact[i] = erf_sol(x[i], T, Re);
}
// Explicit solution
memcpy(u_explicit
, u_initial
, NX
* sizeof(double)); explicit_scheme(u_explicit, Re, Nt, dt, dx);
// Crank-Nicolson solution
memcpy(u_cn
, u_initial
, NX
* sizeof(double)); crank_nicolson_scheme(u_cn, Re, Nt, dt, dx);
// Plot results for explicit scheme vs exact solution
fprintf(gp
, "plot '-' title 'Explicit Re=%.1f, T=%.2f' with lines, '-' title 'Exact' with lines\n", Re
, T
); for (int i = 0; i < NX; ++i) {
fprintf(gp
, "%f %f\n", x
[i
], u_explicit
[i
]); }
for (int i = 0; i < NX; ++i) {
fprintf(gp
, "%f %f\n", x
[i
], u_exact
[i
]); }
// Plot error for explicit scheme
fprintf(gp
, "plot '-' title 'Error Explicit' with lines\n"); for (int i = 0; i < NX; ++i) {
fprintf(gp
, "%f %f\n", x
[i
], fabs(u_explicit
[i
] - u_exact
[i
])); }
// Plot results for Crank-Nicolson scheme vs exact solution
fprintf(gp
, "plot '-' title 'Crank-Nicolson Re=%.1f, T=%.2f' with lines, '-' title 'Exact' with lines\n", Re
, T
); for (int i = 0; i < NX; ++i) {
fprintf(gp
, "%f %f\n", x
[i
], u_cn
[i
]); }
for (int i = 0; i < NX; ++i) {
fprintf(gp
, "%f %f\n", x
[i
], u_exact
[i
]); }
// Plot error for Crank-Nicolson scheme
fprintf(gp
, "plot '-' title 'Error Crank-Nicolson' with lines\n"); for (int i = 0; i < NX; ++i) {
fprintf(gp
, "%f %f\n", x
[i
], fabs(u_cn
[i
] - u_exact
[i
])); }
}
}
pclose(gp);
return 0;
}
// Error function approximation
double erf_sol(double x, double t, double Re) {
return 0.5 * (1 - erf
(x
/ (2 * sqrt((1 / Re
) * t
)))); }
// Explicit scheme function
void explicit_scheme(double *u, double Re, int Nt, double dt, double dx) {
double u_new[NX];
for (int n = 0; n < Nt; ++n) {
memcpy(u_new
, u
, NX
* sizeof(double)); for (int i = 1; i < NX - 1; ++i) {
u_new[i] = u[i] - dt * u[i] * (u[i + 1] - u[i - 1]) / (2 * dx)
+ (dt / Re) * (u[i + 1] - 2 * u[i] + u[i - 1]) / (dx * dx);
}
memcpy(u
, u_new
, NX
* sizeof(double)); }
}
// Crank-Nicolson scheme function
void crank_nicolson_scheme(double *u, double Re, int Nt, double dt, double dx) {
double alpha = dt / (2 * dx * dx * Re);
double B[NX];
double main_diag[NX], upper_diag[NX - 1], lower_diag[NX - 1];
// Initialize the diagonals
for (int i = 0; i < NX; ++i) {
main_diag[i] = 1 + 2 * alpha;
if (i < NX - 1) {
upper_diag[i] = -alpha;
lower_diag[i] = -alpha;
}
}
for (int n = 0; n < Nt; ++n) {
for (int i = 1; i < NX - 1; ++i) {
B[i] = u[i] - dt * u[i] * (u[i + 1] - u[i - 1]) / (4 * dx)
+ alpha * (u[i + 1] - 2 * u[i] + u[i - 1]);
}
B[0] = 1.0; // Left boundary condition
B[NX - 1] = 0.0; // Right boundary condition
// Thomas Algorithm (tridiagonal matrix solver)
// Forward elimination
for (int i = 1; i < NX; ++i) {
double m = upper_diag[i - 1] / main_diag[i - 1];
main_diag[i] -= m * lower_diag[i - 1];
B[i] -= m * B[i - 1];
}
// Back substitution
u[NX - 1] = B[NX - 1] / main_diag[NX - 1];
for (int i = NX - 2; i >= 0; --i) {
u[i] = (B[i] - lower_diag[i] * u[i + 1]) / main_diag[i];
}
}
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPG1hdGguaD4KI2luY2x1ZGUgPHN0cmluZy5oPgoKI2RlZmluZSBOWCAxMDAgICAgICAgICAgICAgICAgICAvLyBOdW1iZXIgb2Ygc3BhdGlhbCBwb2ludHMKI2RlZmluZSBOVF9UT1RBTCA1MDAgICAgICAgICAgICAvLyBUb3RhbCB0aW1lIHN0ZXBzIGZvciBUID0gMC41CiNkZWZpbmUgWF9NQVggMS4wICAgICAgICAgICAgICAgLy8gTWF4aW11bSB4IHZhbHVlCiNkZWZpbmUgUEkgMy4xNDE1OTI2NTM1ODk3OTMKCi8vIEZ1bmN0aW9uIHByb3RvdHlwZXMKZG91YmxlIGVyZl9zb2woZG91YmxlIHgsIGRvdWJsZSB0LCBkb3VibGUgUmUpOwp2b2lkIGV4cGxpY2l0X3NjaGVtZShkb3VibGUgKnUsIGRvdWJsZSBSZSwgaW50IE50LCBkb3VibGUgZHQsIGRvdWJsZSBkeCk7CnZvaWQgY3Jhbmtfbmljb2xzb25fc2NoZW1lKGRvdWJsZSAqdSwgZG91YmxlIFJlLCBpbnQgTnQsIGRvdWJsZSBkdCwgZG91YmxlIGR4KTsKCi8vIE1haW4gZnVuY3Rpb24KaW50IG1haW4oKSB7CiAgICBkb3VibGUgeFtOWF0sIHVfaW5pdGlhbFtOWF07CiAgICBkb3VibGUgVF92YWx1ZXNbXSA9IHswLjM2LCAwLjQ3fTsgICAgICAvLyBUaW1lcyB0byBldmFsdWF0ZSB0aGUgc29sdXRpb24KICAgIGRvdWJsZSBSZV92YWx1ZXNbXSA9IHsxMCwgNTB9OyAgICAgICAgICAvLyBSZXlub2xkcyBudW1iZXJzCiAgICBkb3VibGUgdV9leGFjdFtOWF0sIHVfZXhwbGljaXRbTlhdLCB1X2NuW05YXTsKICAgIGRvdWJsZSBkdCA9IDAuNSAvIE5UX1RPVEFMOyAgICAgICAgICAgICAvLyBUaW1lIHN0ZXAgc2l6ZQogICAgZG91YmxlIGR4ID0gMiAqIFhfTUFYIC8gKE5YIC0gMSk7ICAgICAgLy8gU3BhdGlhbCBzdGVwIHNpemUKCiAgICAvLyBHZW5lcmF0ZSBncmlkIGFuZCBpbml0aWFsaXplIGNvbmRpdGlvbnMKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgTlg7ICsraSkgewogICAgICAgIHhbaV0gPSAtWF9NQVggKyBpICogZHg7CiAgICAgICAgdV9pbml0aWFsW2ldID0gKHhbaV0gPCAwKSA/IDEuMCA6IDAuMDsgLy8gSW5pdGlhbCBjb25kaXRpb24KICAgIH0KCiAgICAvLyBPcGVuIGdudXBsb3QKICAgIEZJTEUgKmdwID0gcG9wZW4oImdudXBsb3QgLXBlcnNpc3RlbnQiLCAidyIpOwogICAgZnByaW50ZihncCwgInNldCBtdWx0aXBsb3QgbGF5b3V0IDIsMlxuIik7CgogICAgZm9yIChpbnQgciA9IDA7IHIgPCAyOyArK3IpIHsKICAgICAgICBkb3VibGUgUmUgPSBSZV92YWx1ZXNbcl07CgogICAgICAgIGZvciAoaW50IHRfaWR4ID0gMDsgdF9pZHggPCAyOyArK3RfaWR4KSB7CiAgICAgICAgICAgIGRvdWJsZSBUID0gVF92YWx1ZXNbdF9pZHhdOwogICAgICAgICAgICBpbnQgTnQgPSAoaW50KShUIC8gZHQpOyAgLy8gTnVtYmVyIG9mIHRpbWUgc3RlcHMKCiAgICAgICAgICAgIC8vIEV4YWN0IHNvbHV0aW9uCiAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgTlg7ICsraSkgewogICAgICAgICAgICAgICAgdV9leGFjdFtpXSA9IGVyZl9zb2woeFtpXSwgVCwgUmUpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBFeHBsaWNpdCBzb2x1dGlvbgogICAgICAgICAgICBtZW1jcHkodV9leHBsaWNpdCwgdV9pbml0aWFsLCBOWCAqIHNpemVvZihkb3VibGUpKTsKICAgICAgICAgICAgZXhwbGljaXRfc2NoZW1lKHVfZXhwbGljaXQsIFJlLCBOdCwgZHQsIGR4KTsKCiAgICAgICAgICAgIC8vIENyYW5rLU5pY29sc29uIHNvbHV0aW9uCiAgICAgICAgICAgIG1lbWNweSh1X2NuLCB1X2luaXRpYWwsIE5YICogc2l6ZW9mKGRvdWJsZSkpOwogICAgICAgICAgICBjcmFua19uaWNvbHNvbl9zY2hlbWUodV9jbiwgUmUsIE50LCBkdCwgZHgpOwoKICAgICAgICAgICAgLy8gUGxvdCByZXN1bHRzIGZvciBleHBsaWNpdCBzY2hlbWUgdnMgZXhhY3Qgc29sdXRpb24KICAgICAgICAgICAgZnByaW50ZihncCwgInBsb3QgJy0nIHRpdGxlICdFeHBsaWNpdCBSZT0lLjFmLCBUPSUuMmYnIHdpdGggbGluZXMsICctJyB0aXRsZSAnRXhhY3QnIHdpdGggbGluZXNcbiIsIFJlLCBUKTsKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBOWDsgKytpKSB7CiAgICAgICAgICAgICAgICBmcHJpbnRmKGdwLCAiJWYgJWZcbiIsIHhbaV0sIHVfZXhwbGljaXRbaV0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZwcmludGYoZ3AsICJlXG4iKTsKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBOWDsgKytpKSB7CiAgICAgICAgICAgICAgICBmcHJpbnRmKGdwLCAiJWYgJWZcbiIsIHhbaV0sIHVfZXhhY3RbaV0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZwcmludGYoZ3AsICJlXG4iKTsKCiAgICAgICAgICAgIC8vIFBsb3QgZXJyb3IgZm9yIGV4cGxpY2l0IHNjaGVtZQogICAgICAgICAgICBmcHJpbnRmKGdwLCAicGxvdCAnLScgdGl0bGUgJ0Vycm9yIEV4cGxpY2l0JyB3aXRoIGxpbmVzXG4iKTsKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBOWDsgKytpKSB7CiAgICAgICAgICAgICAgICBmcHJpbnRmKGdwLCAiJWYgJWZcbiIsIHhbaV0sIGZhYnModV9leHBsaWNpdFtpXSAtIHVfZXhhY3RbaV0pKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBmcHJpbnRmKGdwLCAiZVxuIik7CgogICAgICAgICAgICAvLyBQbG90IHJlc3VsdHMgZm9yIENyYW5rLU5pY29sc29uIHNjaGVtZSB2cyBleGFjdCBzb2x1dGlvbgogICAgICAgICAgICBmcHJpbnRmKGdwLCAicGxvdCAnLScgdGl0bGUgJ0NyYW5rLU5pY29sc29uIFJlPSUuMWYsIFQ9JS4yZicgd2l0aCBsaW5lcywgJy0nIHRpdGxlICdFeGFjdCcgd2l0aCBsaW5lc1xuIiwgUmUsIFQpOwogICAgICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IE5YOyArK2kpIHsKICAgICAgICAgICAgICAgIGZwcmludGYoZ3AsICIlZiAlZlxuIiwgeFtpXSwgdV9jbltpXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZnByaW50ZihncCwgImVcbiIpOwogICAgICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IE5YOyArK2kpIHsKICAgICAgICAgICAgICAgIGZwcmludGYoZ3AsICIlZiAlZlxuIiwgeFtpXSwgdV9leGFjdFtpXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZnByaW50ZihncCwgImVcbiIpOwoKICAgICAgICAgICAgLy8gUGxvdCBlcnJvciBmb3IgQ3JhbmstTmljb2xzb24gc2NoZW1lCiAgICAgICAgICAgIGZwcmludGYoZ3AsICJwbG90ICctJyB0aXRsZSAnRXJyb3IgQ3JhbmstTmljb2xzb24nIHdpdGggbGluZXNcbiIpOwogICAgICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IE5YOyArK2kpIHsKICAgICAgICAgICAgICAgIGZwcmludGYoZ3AsICIlZiAlZlxuIiwgeFtpXSwgZmFicyh1X2NuW2ldIC0gdV9leGFjdFtpXSkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZwcmludGYoZ3AsICJlXG4iKTsKICAgICAgICB9CiAgICB9CgogICAgZnByaW50ZihncCwgInVuc2V0IG11bHRpcGxvdFxuIik7CiAgICBwY2xvc2UoZ3ApOwoKICAgIHJldHVybiAwOwp9CgovLyBFcnJvciBmdW5jdGlvbiBhcHByb3hpbWF0aW9uCmRvdWJsZSBlcmZfc29sKGRvdWJsZSB4LCBkb3VibGUgdCwgZG91YmxlIFJlKSB7CiAgICByZXR1cm4gMC41ICogKDEgLSBlcmYoeCAvICgyICogc3FydCgoMSAvIFJlKSAqIHQpKSkpOwp9CgovLyBFeHBsaWNpdCBzY2hlbWUgZnVuY3Rpb24Kdm9pZCBleHBsaWNpdF9zY2hlbWUoZG91YmxlICp1LCBkb3VibGUgUmUsIGludCBOdCwgZG91YmxlIGR0LCBkb3VibGUgZHgpIHsKICAgIGRvdWJsZSB1X25ld1tOWF07CgogICAgZm9yIChpbnQgbiA9IDA7IG4gPCBOdDsgKytuKSB7CiAgICAgICAgbWVtY3B5KHVfbmV3LCB1LCBOWCAqIHNpemVvZihkb3VibGUpKTsKICAgICAgICBmb3IgKGludCBpID0gMTsgaSA8IE5YIC0gMTsgKytpKSB7CiAgICAgICAgICAgIHVfbmV3W2ldID0gdVtpXSAtIGR0ICogdVtpXSAqICh1W2kgKyAxXSAtIHVbaSAtIDFdKSAvICgyICogZHgpCiAgICAgICAgICAgICAgICAgICAgICAgICsgKGR0IC8gUmUpICogKHVbaSArIDFdIC0gMiAqIHVbaV0gKyB1W2kgLSAxXSkgLyAoZHggKiBkeCk7CiAgICAgICAgfQogICAgICAgIG1lbWNweSh1LCB1X25ldywgTlggKiBzaXplb2YoZG91YmxlKSk7CiAgICB9Cn0KCi8vIENyYW5rLU5pY29sc29uIHNjaGVtZSBmdW5jdGlvbgp2b2lkIGNyYW5rX25pY29sc29uX3NjaGVtZShkb3VibGUgKnUsIGRvdWJsZSBSZSwgaW50IE50LCBkb3VibGUgZHQsIGRvdWJsZSBkeCkgewogICAgZG91YmxlIGFscGhhID0gZHQgLyAoMiAqIGR4ICogZHggKiBSZSk7CiAgICBkb3VibGUgQltOWF07CiAgICBkb3VibGUgbWFpbl9kaWFnW05YXSwgdXBwZXJfZGlhZ1tOWCAtIDFdLCBsb3dlcl9kaWFnW05YIC0gMV07CgogICAgLy8gSW5pdGlhbGl6ZSB0aGUgZGlhZ29uYWxzCiAgICBmb3IgKGludCBpID0gMDsgaSA8IE5YOyArK2kpIHsKICAgICAgICBtYWluX2RpYWdbaV0gPSAxICsgMiAqIGFscGhhOwogICAgICAgIGlmIChpIDwgTlggLSAxKSB7CiAgICAgICAgICAgIHVwcGVyX2RpYWdbaV0gPSAtYWxwaGE7CiAgICAgICAgICAgIGxvd2VyX2RpYWdbaV0gPSAtYWxwaGE7CiAgICAgICAgfQogICAgfQoKICAgIGZvciAoaW50IG4gPSAwOyBuIDwgTnQ7ICsrbikgewogICAgICAgIGZvciAoaW50IGkgPSAxOyBpIDwgTlggLSAxOyArK2kpIHsKICAgICAgICAgICAgQltpXSA9IHVbaV0gLSBkdCAqIHVbaV0gKiAodVtpICsgMV0gLSB1W2kgLSAxXSkgLyAoNCAqIGR4KQogICAgICAgICAgICAgICAgICAgKyBhbHBoYSAqICh1W2kgKyAxXSAtIDIgKiB1W2ldICsgdVtpIC0gMV0pOwogICAgICAgIH0KICAgICAgICBCWzBdID0gMS4wOyAgLy8gTGVmdCBib3VuZGFyeSBjb25kaXRpb24KICAgICAgICBCW05YIC0gMV0gPSAwLjA7ICAvLyBSaWdodCBib3VuZGFyeSBjb25kaXRpb24KCiAgICAgICAgLy8gVGhvbWFzIEFsZ29yaXRobSAodHJpZGlhZ29uYWwgbWF0cml4IHNvbHZlcikKICAgICAgICAvLyBGb3J3YXJkIGVsaW1pbmF0aW9uCiAgICAgICAgZm9yIChpbnQgaSA9IDE7IGkgPCBOWDsgKytpKSB7CiAgICAgICAgICAgIGRvdWJsZSBtID0gdXBwZXJfZGlhZ1tpIC0gMV0gLyBtYWluX2RpYWdbaSAtIDFdOwogICAgICAgICAgICBtYWluX2RpYWdbaV0gLT0gbSAqIGxvd2VyX2RpYWdbaSAtIDFdOwogICAgICAgICAgICBCW2ldIC09IG0gKiBCW2kgLSAxXTsKICAgICAgICB9CgogICAgICAgIC8vIEJhY2sgc3Vic3RpdHV0aW9uCiAgICAgICAgdVtOWCAtIDFdID0gQltOWCAtIDFdIC8gbWFpbl9kaWFnW05YIC0gMV07CiAgICAgICAgZm9yIChpbnQgaSA9IE5YIC0gMjsgaSA+PSAwOyAtLWkpIHsKICAgICAgICAgICAgdVtpXSA9IChCW2ldIC0gbG93ZXJfZGlhZ1tpXSAqIHVbaSArIDFdKSAvIG1haW5fZGlhZ1tpXTsKICAgICAgICB9CiAgICB9Cn0K