Skip to content

Commit 3ebd689

Browse files
authored
Merge pull request #146 from csrc-sdsu/terzaghi1D
Terzaghi-1D: Example 1D diffusion of pressure to model consolidation, the process of transient fluid flow through a porous medium that deforms over time.
2 parents 280e45f + c6f0ae9 commit 3ebd689

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

examples/matlab/terzaghi1D.m

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
% -------------------------------------------------------------------------
2+
% Terzaghi One-Dimensional Consolidation Example
3+
%
4+
% Consolidation is the process of transient fluid flow through a porous
5+
% medium that deforms over time.
6+
%
7+
% A constant compressive face load of P0 = 10 MPa is applied at the
8+
% left boundary (x = 0 m) of a saturated porous soil matrix.
9+
%
10+
% Zero displacement is assumed at the right boundary (x = L = 25 m),
11+
% representing a fixed wall or support.
12+
%
13+
% The matrix is assumed to be fully saturated, and fluid drainage is
14+
% permitted only at the loaded boundary (x = 0 m).
15+
%
16+
% The MOLE Laplacian operator is used to compute the excess pore pressure
17+
% p(x, t), satisfies a one-dimensional diffusion equation for pressure.
18+
%
19+
% The domain is defined on the interval x ∈ [0, L] meters.
20+
%
21+
% The simulation compares the MOLE-based numerical solution to an
22+
% analytical benchmark solution derived using Fourier series.
23+
% -------------------------------------------------------------------------
24+
25+
%%
26+
clc;
27+
close all;
28+
29+
addpath('../../src/matlab'); % MOLE operator path
30+
31+
%% Parameters
32+
P0 = 10e6; % Face load in Pascals
33+
cf = 1e-4; % Diffusion constant
34+
l = 25; % Domain length in meters
35+
k = 2; % MOLE operator order
36+
m = 50; % Number of cells
37+
38+
% Spatial discretization
39+
a = 0; % Left boundary of the domain [m]
40+
b = l; % Right boundary of the domain [m]
41+
dx = (b - a)/m; % Cell width (uniform grid spacing) [m]
42+
xgrid = [a a+dx/2 : dx : b-dx/2 b]; % Staggered grid with ghost nodes at boundaries
43+
% xgrid has m+2 points:
44+
% - ghost cell at a (Dirichlet BC)
45+
% - m internal nodes
46+
% - ghost cell at b (Neumann BC)
47+
48+
% Times to evaluate (in hours)
49+
times_hr = [1, 10, 40, 70]; % Time snapshots in hours for comparison
50+
times_sec = times_hr * 3600; % Convert time points to seconds for simulation
51+
52+
% Fluid properties
53+
K = 1e-12; % Permeability [m^2]
54+
mu = 1e-3; % Dynamic viscosity [Pa·s]
55+
rho = 1000; % Fluid density [kg/m^3]
56+
g = 9.81; % Gravity [m/s^2]
57+
58+
%% Numerical (MOLE) Solution
59+
L = lap(k, m, dx); % Mimetic Laplacian operator for diffusion
60+
G = grad(k, m, dx); % Mimetic gradient operator for Darcy flux
61+
62+
% Boundary modifications to Laplacian
63+
L(1,:) = 0; L(end,:) = 0;
64+
65+
p_numerical = zeros(length(xgrid), length(times_sec)); % Pressure field [Pa]
66+
q_numerical = zeros(m+1, length(times_sec)); % Darcy flux [m/s] (size = m+1)
67+
68+
% Loop over each specified final time
69+
for i = 1:length(times_sec)
70+
t_final = times_sec(i);
71+
dt = 0.03;
72+
nsteps = round(t_final / dt);
73+
74+
% Uniform Initial Condition : p(x,0) = P0
75+
p = P0 * ones(size(xgrid))';
76+
77+
% Time integration using Forward Euler
78+
for step = 1:nsteps
79+
p = p + dt * cf * (L * p);
80+
p(1) = 0; % Dirichlet BC at x = 0
81+
p(end) = p(end-1); % Neumann BC at x = L
82+
end
83+
84+
p_numerical(:,i) = p;
85+
86+
% Compute Darcy flux (numerical)
87+
dpdx = G * p;
88+
q = - (K / mu) * (dpdx - rho * g);
89+
q_numerical(:,i) = q(1:m+1);
90+
91+
% Print numerical results
92+
fprintf('\nNumerical results at t = %.2f hr:\n', times_hr(i));
93+
fprintf('| x (m) | Numerical p [Pa] | Darcy Flux [m/s] |\n');
94+
fprintf('|---------------|------------------|------------------|\n');
95+
for j = 1:m+1
96+
fprintf('| %13.6f | %16.6e | %16.6e |\n', xgrid(j), p_numerical(j,i), q_numerical(j,i));
97+
end
98+
end
99+
100+
%% Analytical Solution
101+
N_max = 100; % Number of Fourier series terms
102+
p_analytical = zeros(length(xgrid), length(times_sec)); % Pressure field [Pa]
103+
q_analytical = zeros(m+1, length(times_sec)); % Darcy flux [m/s] (size = m+1)
104+
105+
% Loop over all time snapshots
106+
for i = 1:length(times_sec)
107+
t = times_sec(i);
108+
p = zeros(size(xgrid));
109+
110+
% Compute analytical solution using truncated Fourier sine series
111+
for N = 0:N_max
112+
n = 2*N + 1; % Odd terms only (satisfies boundary conditions)
113+
term = (1/n) * sin(n*pi*xgrid/(2*l)) .* exp(-(n^2)*(pi^2)*cf*t/(4*l^2));
114+
p = p + term;
115+
end
116+
p = (4/pi) * P0 * p;
117+
p_analytical(:,i) = p;
118+
119+
% Compute Darcy flux (analytical)
120+
dpdx = gradient(p, dx); % basic gradient
121+
q = - (K / mu) * (dpdx - rho * g);
122+
q_analytical(:,i) = q(1:m+1);
123+
124+
% Print analytical results
125+
fprintf('\nAnalytical results at t = %.2f hr:\n', times_hr(i));
126+
fprintf('| x (m) | Analytical p [Pa] | Darcy Flux [m/s] |\n');
127+
fprintf('|---------------|-------------------|------------------|\n');
128+
for j = 1:m+1
129+
fprintf('| %13.6f | %18.6e | %16.6e |\n', xgrid(j), p_analytical(j,i), q_analytical(j,i));
130+
end
131+
end
132+
133+
%% Combined Plot
134+
figure('Name','Terzaghi one-dimensional consolidation');
135+
set(gcf,'Color','white');
136+
137+
% Top subplot: MOLE numerical
138+
subplot(2,1,1);
139+
hold on;
140+
for i = 1:length(times_sec)
141+
semilogy(xgrid, p_numerical(:,i)/1e6, '-o', 'DisplayName', [num2str(times_hr(i)) ' hr']);
142+
end
143+
title('MOLE Numerical Solution');
144+
ylabel('Excess Pore Pressure p(x,t) [MPa]');
145+
axis([0 l 1e-3 10]);
146+
legend('Location', 'southeast');
147+
grid on;
148+
149+
% Bottom subplot: Analytical
150+
subplot(2,1,2);
151+
hold on;
152+
for i = 1:length(times_sec)
153+
semilogy(xgrid, p_analytical(:,i)/1e6, '--s', 'DisplayName', [num2str(times_hr(i)) ' hr']);
154+
end
155+
title('Analytical Benchmark Solution');
156+
xlabel('x (m)');
157+
ylabel('Excess Pore Pressure p(x,t) [MPa]');
158+
axis([0 l 1e-3 10]);
159+
legend('Location', 'southeast');
160+
grid on;
161+
162+
%% Print relative L2 errors
163+
fprintf('\nRelative L2 Errors (Numerical vs Analytical):\n');
164+
fprintf('| Time [hr] | Pressure Error | Darcy Flux Error |\n');
165+
fprintf('|------------------|--------------------|---------------------|\n');
166+
for i = 1:length(times_hr)
167+
% L2 error for pressure
168+
rel_err_p = norm(p_numerical(:,i) - p_analytical(:,i)) / norm(p_analytical(:,i));
169+
170+
% L2 error for flux
171+
rel_err_q = norm(q_numerical(:,i) - q_analytical(:,i)) / norm(q_analytical(:,i));
172+
173+
% Print in table format
174+
fprintf('| %16.2f | %18.6e | %19.6e |\n', times_hr(i), rel_err_p, rel_err_q);
175+
end

0 commit comments

Comments
 (0)