|
12 | 12 | m = 50; % Number of cells |
13 | 13 |
|
14 | 14 | % Spatial discretization |
15 | | -a = 0; |
16 | | -b = l; |
17 | | -dx = (b - a)/m; |
18 | | -xgrid = [a a+dx/2 : dx : b-dx/2 b]; % Staggered grid |
| 15 | +a = 0; % Left boundary of the domain [m] |
| 16 | +b = l; % Right boundary of the domain [m] |
| 17 | +dx = (b - a)/m; % Cell width (uniform grid spacing) [m] |
| 18 | +xgrid = [a a+dx/2 : dx : b-dx/2 b]; % Staggered grid with ghost nodes at boundaries |
| 19 | +% xgrid has m+2 points: |
| 20 | +% - ghost cell at a (Dirichlet BC) |
| 21 | +% - m internal nodes |
| 22 | +% - ghost cell at b (Neumann BC) |
19 | 23 |
|
20 | 24 | % Times to evaluate (in hours) |
21 | | -times_hr = [1, 10, 40, 70]; |
22 | | -times_sec = times_hr * 3600; |
| 25 | +times_hr = [1, 10, 40, 70]; % Time snapshots in hours for comparison |
| 26 | +times_sec = times_hr * 3600; % Convert time points to seconds for simulation |
23 | 27 |
|
24 | 28 | % Fluid properties |
25 | 29 | K = 1e-12; % Permeability [m^2] |
|
32 | 36 | G = grad(k, m, dx); |
33 | 37 | L(1,:) = 0; L(end,:) = 0; |
34 | 38 |
|
35 | | -p_numerical = zeros(length(xgrid), length(times_sec)); |
| 39 | +p_numerical = zeros(length(xgrid), length(times_sec)); % Pressure field [Pa] |
| 40 | +q_numerical = zeros(m+1, length(times_sec)); % Darcy flux [m/s] (size = m+1) |
| 41 | + |
| 42 | +% Loop over each specified final time |
36 | 43 | for i = 1:length(times_sec) |
37 | 44 | t_final = times_sec(i); |
38 | 45 | dt = 0.03; |
39 | 46 | nsteps = round(t_final / dt); |
40 | 47 |
|
41 | | - % Uniform Initial Condition |
| 48 | + % Uniform Initial Condition : p(x,0) = P0 |
42 | 49 | p = P0 * ones(size(xgrid))'; |
43 | 50 |
|
| 51 | + % Time integration using Forward Euler |
44 | 52 | for step = 1:nsteps |
45 | 53 | p = p + dt * cf * (L * p); |
46 | | - p(1) = 0; % Dirichlet BC |
47 | | - p(end) = p(end-1); % Neumann BC |
| 54 | + p(1) = 0; % Dirichlet BC at x = 0 |
| 55 | + p(end) = p(end-1); % Neumann BC at x = L |
48 | 56 | end |
49 | 57 |
|
50 | 58 | p_numerical(:,i) = p; |
| 59 | + |
| 60 | + % Compute Darcy flux (numerical) |
| 61 | + dpdx = G * p; |
| 62 | + q = - (K / mu) * (dpdx - rho * g); |
| 63 | + q_numerical(:,i) = q(1:m+1); |
| 64 | + |
| 65 | + % Print numerical results |
| 66 | + fprintf('\nNumerical results at t = %.2f hr:\n', times_hr(i)); |
| 67 | + fprintf('| x (m) | Numerical p [Pa] | Darcy Flux [m/s] |\n'); |
| 68 | + fprintf('|---------------|------------------|------------------|\n'); |
| 69 | + for j = 1:m+1 |
| 70 | + fprintf('| %13.6f | %16.6e | %16.6e |\n', xgrid(j), p_numerical(j,i), q_numerical(j,i)); |
| 71 | + end |
51 | 72 | end |
52 | 73 |
|
53 | 74 | %% Analytical Solution |
54 | | -N_max = 100; |
55 | | -p_analytical = zeros(length(xgrid), length(times_sec)); |
| 75 | +N_max = 100; % Number of Fourier series terms |
| 76 | +p_analytical = zeros(length(xgrid), length(times_sec)); % Pressure field [Pa] |
| 77 | +q_analytical = zeros(m+1, length(times_sec)); % Darcy flux [m/s] (size = m+1) |
| 78 | + |
| 79 | +% Loop over all time snapshots |
56 | 80 | for i = 1:length(times_sec) |
57 | 81 | t = times_sec(i); |
58 | 82 | p = zeros(size(xgrid)); |
| 83 | + |
| 84 | + % Compute analytical solution using truncated Fourier sine series |
59 | 85 | for N = 0:N_max |
60 | | - n = 2*N + 1; |
| 86 | + n = 2*N + 1; % Odd terms only (satisfies boundary conditions) |
61 | 87 | term = (1/n) * sin(n*pi*xgrid/(2*l)) .* exp(-(n^2)*(pi^2)*cf*t/(4*l^2)); |
62 | 88 | p = p + term; |
63 | 89 | end |
64 | | - p_analytical(:,i) = (4/pi) * P0 * p; |
| 90 | + p = (4/pi) * P0 * p; |
| 91 | + p_analytical(:,i) = p; |
| 92 | + |
| 93 | + % Compute Darcy flux (analytical) |
| 94 | + dpdx = gradient(p, dx); % basic gradient |
| 95 | + q = - (K / mu) * (dpdx - rho * g); |
| 96 | + q_analytical(:,i) = q(1:m+1); |
| 97 | + |
| 98 | + % Print analytical results |
| 99 | + fprintf('\nAnalytical results at t = %.2f hr:\n', times_hr(i)); |
| 100 | + fprintf('| x (m) | Analytical p [Pa] | Darcy Flux [m/s] |\n'); |
| 101 | + fprintf('|---------------|-------------------|------------------|\n'); |
| 102 | + for j = 1:m+1 |
| 103 | + fprintf('| %13.6f | %18.6e | %16.6e |\n', xgrid(j), p_analytical(j,i), q_analytical(j,i)); |
| 104 | + end |
65 | 105 | end |
66 | 106 |
|
67 | 107 | %% Combined Plot |
68 | 108 | figure('Name','Terzaghi one-dimensional consolidation'); |
69 | 109 | set(gcf,'Color','white'); |
| 110 | + |
70 | 111 | % Top subplot: MOLE numerical |
71 | 112 | subplot(2,1,1); |
72 | 113 | hold on; |
|
94 | 135 |
|
95 | 136 | %% Print relative L2 errors |
96 | 137 | fprintf('\nRelative L2 Errors (Numerical vs Analytical):\n'); |
| 138 | +fprintf('| Time [hr] | Pressure Error | Darcy Flux Error |\n'); |
| 139 | +fprintf('|------------------|--------------------|---------------------|\n'); |
97 | 140 | for i = 1:length(times_hr) |
98 | | - rel_err = norm(p_numerical(:,i) - p_analytical(:,i)) / norm(p_analytical(:,i)); |
99 | | - fprintf('t = %.2f hr: %.6e\n', times_hr(i), rel_err); |
| 141 | + % L2 error for pressure |
| 142 | + rel_err_p = norm(p_numerical(:,i) - p_analytical(:,i)) / norm(p_analytical(:,i)); |
| 143 | + |
| 144 | + % L2 error for flux |
| 145 | + rel_err_q = norm(q_numerical(:,i) - q_analytical(:,i)) / norm(q_analytical(:,i)); |
| 146 | + |
| 147 | + % Print in table format |
| 148 | + fprintf('| %16.2f | %18.6e | %19.6e |\n', times_hr(i), rel_err_p, rel_err_q); |
100 | 149 | end |
0 commit comments