mirror of
https://git.gfz-potsdam.de/naaice/tug.git
synced 2025-12-13 17:38:23 +01:00
MDL: Written down 2D explicit FTCS scheme in docs/ADI_scheme.org; rough implementation in scripts/Adi2D_Reference.R
This commit is contained in:
parent
adb2e325be
commit
459922629d
@ -1,7 +1,7 @@
|
||||
#+TITLE: Numerical solution of diffusion equation in 2D with ADI Scheme
|
||||
#+TITLE: Finite Difference Schemes for the numerical solution of heterogeneous diffusion equation in 2D
|
||||
#+LaTeX_CLASS_OPTIONS: [a4paper,10pt]
|
||||
#+LATEX_HEADER: \usepackage{fullpage}
|
||||
#+LATEX_HEADER: \usepackage{amsmath, systeme}
|
||||
#+LATEX_HEADER: \usepackage{amsmath, systeme, cancel, xcolor}
|
||||
#+OPTIONS: toc:nil
|
||||
|
||||
|
||||
@ -308,8 +308,8 @@ form:
|
||||
|
||||
* Heterogeneous diffusion
|
||||
|
||||
If the diffusion coefficient $\alpha$ is spatially variable, [[eqn:1]] can
|
||||
be rewritten:
|
||||
If the diffusion coefficient $\alpha$ is spatially variable, equation
|
||||
[[eqn:1]] can be rewritten as:
|
||||
|
||||
#+NAME: eqn:hetdiff
|
||||
\begin{align}
|
||||
@ -391,8 +391,8 @@ concentrations.
|
||||
** Direct discretization
|
||||
|
||||
As noted in literature (LeVeque and Numerical Recipes) a better way is
|
||||
to discretize directly the physical problem ([[eqn:hetdiff]]) at points
|
||||
halfway between grid points:
|
||||
to discretize directly the physical problem (eq. [[eqn:hetdiff]]) at
|
||||
points halfway between grid points:
|
||||
|
||||
\begin{align*}
|
||||
\begin{cases}
|
||||
@ -401,15 +401,18 @@ halfway between grid points:
|
||||
\end{cases}
|
||||
\end{align*}
|
||||
|
||||
\noindent A further differentiation gives us the centered
|
||||
\noindent A further differentiation gives us the spatially centered
|
||||
approximation of $\frac{\partial}{\partial x} \left(\alpha(x)
|
||||
\frac{\partial C }{\partial x}\right)$:
|
||||
|
||||
\begin{align*}
|
||||
#+NAME: eqn:CS_het
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
\frac{\partial}{\partial x} \left(\alpha(x)
|
||||
\frac{\partial C }{\partial x}\right)(x_i) & \simeq \frac{1}{\Delta x}\left[\alpha_{i+1/2} \left( \frac{C_{i+1} -C_{i}}{\Delta x} \right) - \alpha_{i-1/2} \left( \frac{C_{i} -C_{i-1}}{\Delta x} \right) \right]\\
|
||||
&\displaystyle =\frac{1}{\Delta x^2} \left[ \alpha_{i+1/2}C_{i+1} - (\alpha_{i+1/2}+\alpha_{i-1/2}) C_{i} + \alpha_{i-1/2}C_{i-1}\right]
|
||||
\end{align*}
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
\noindent The ADI scheme with this approach becomes:
|
||||
|
||||
@ -439,3 +442,98 @@ explicit terms, the two sweeps become:
|
||||
\end{aligned}
|
||||
\right.
|
||||
\end{equation}
|
||||
|
||||
\bigskip
|
||||
|
||||
\noindent The "interblock" diffusion coefficients $\alpha_{i+1/2,j}$
|
||||
can be arithmetic mean:
|
||||
|
||||
\[
|
||||
\displaystyle \alpha_{i+1/2, j} = \displaystyle \frac{\alpha_{i+1, j} + \alpha_{i, j}}{2}
|
||||
\]
|
||||
|
||||
\noindent or the harmonic mean:
|
||||
|
||||
\[
|
||||
\displaystyle \alpha_{i+1/2, j} = \displaystyle \frac{2}{\frac{1}{\alpha_{i+1, j}} + \frac{1}{\alpha_{i, j}}}
|
||||
\]
|
||||
|
||||
|
||||
|
||||
\pagebreak
|
||||
|
||||
* Explicit scheme for 2D heterogeneous diffusion
|
||||
|
||||
A classical explicit FTCS scheme (forward in time, central in space)
|
||||
for 2D heterogeneous diffusion can be expressed simply leveraging the
|
||||
discretization of equation [[eqn:CS_het]]:
|
||||
|
||||
#+NAME: eqn:2DHeterFTCS
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
\frac{C_{i,j}^{t+1} - C_{i,j}^{t}}{\Delta t} = & \frac{1}{\Delta x^2} \left[ \alpha^x_{i+1/2, j}C^t_{i+1, j} - (\alpha^x_{i+1/2, j} + \alpha^x_{i-1/2, j}) C^t_{i,j} + \alpha^x_{i-1/2,j}C^t_{i-1,j}\right] + \\
|
||||
& \frac{1}{\Delta y^2} \left[ \alpha^y_{i, j+1/2}C^t_{i, j+1} - (\alpha^y_{i, j+1/2} + \alpha^y_{i, j-1/2}) C^t_{i,j} + \alpha^y_{i,j-1/2}C^t_{i,j-1}\right]
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
\noindent where in the RHS only the known concentrations at time $t$
|
||||
appear. Rearranging the terms, we get:
|
||||
|
||||
#+NAME: eqn:2DHeterFTCS_final
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
C_{i,j}^{t+1} = & C^t_{i,j} +\\
|
||||
& \frac{\Delta t}{\Delta x^2} \left[ \alpha^x_{i+1/2, j}C^t_{i+1, j} - (\alpha^x_{i+1/2, j} + \alpha^x_{i-1/2, j}) C^t_{i,j} + \alpha^x_{i-1/2,j}C^t_{i-1,j}\right] + \\
|
||||
& \frac{\Delta t}{\Delta y^2} \left[ \alpha^y_{i, j+1/2}C^t_{i, j+1} - (\alpha^y_{i, j+1/2} + \alpha^y_{i, j-1/2}) C^t_{i,j} + \alpha^y_{i,j-1/2}C^t_{i,j-1}\right]
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
The Courant-Friedrichs-Lewy stability criterion for this scheme reads:
|
||||
#+NAME: eqn:CFL2DFTCS
|
||||
\begin{equation}
|
||||
\Delta t \leq \frac{(\Delta x^2, \Delta y^2)}{2 \max(\alpha_{i,j})}
|
||||
\end{equation}
|
||||
|
||||
** Boundary conditions
|
||||
|
||||
In analogy to the treatment of the 1D homogeneous FTCS scheme (cfr
|
||||
section 1), we need to differentiate the domain boundaries ($i=0$ and
|
||||
$i=n_x$; the same applies to $j$ of course) accounting for the
|
||||
discrepancy in the discretization.
|
||||
|
||||
For the zero-th (left) cell, whose center is at $x=dx/2$, we can
|
||||
evaluate the left gradient with the left boundary using such distance,
|
||||
calling $l$ the numerical value of a constant boundary condition,
|
||||
equation [[eqn:CS_het]] becomes:
|
||||
|
||||
#+NAME: eqn:2D_FTCS_left
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
\frac{\partial}{\partial x} \left(\alpha(x)
|
||||
\frac{\partial C }{\partial x}\right)(x_0) & \simeq \frac{1}{\Delta x}\left[\alpha_{i+1/2} \left( \frac{C_{i+1} -C_{i}}{\Delta x} \right) - \alpha_{i} \left( \frac{C_{i} - l }{\frac{\Delta x}{2}} \right) \right]\\
|
||||
&\displaystyle =\frac{1}{\Delta x^2} \left[ \alpha_{i+1/2}C_{i+1} - (\alpha_{i+1/2}+ 2\alpha_i) C_{i} + 2 \alpha_{i}\cdot l\right]
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
\noindent Similarly, for $i=n_x$,
|
||||
|
||||
#+NAME: eqn:2D_FTCS_right
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
\frac{\partial}{\partial x} \left(\alpha(x)
|
||||
\frac{\partial C }{\partial x}\right)(x_n) & \simeq \frac{1}{\Delta x}\left[\alpha_{i} \left( \frac{r -C_{i}}{\frac{\Delta x}{2}} \right) - \alpha_{i-1/2} \left( \frac{C_{i} - C_{i-1}} {\Delta x} \right) \right]\\
|
||||
&\displaystyle =\frac{1}{\Delta x^2} \left[ 2 \alpha_{i} r - (\alpha_{i+1/2}+ 2\alpha_i) C_{i} + \alpha_{i-1/2}\cdot C_{i-1}\right]
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
If on the right boundary we have *closed* or Neumann condition, the
|
||||
left derivative becomes zero and we are left with:
|
||||
|
||||
#+NAME: eqn:2D_FTCS_rightclosed
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
\frac{\partial}{\partial x} \left(\alpha(x)
|
||||
\frac{\partial C }{\partial x}\right)(x_n) & \simeq \frac{1}{\Delta x}\left[\cancel{\alpha_{i+1/2} \left( \frac{C_{i+1} -C_{i}}{\Delta x} \right)} - \alpha_{i-1/2} \left( \frac{C_{i} -C_{i-1}}{\Delta x} \right) \right]\\
|
||||
&\displaystyle =\frac{\alpha_{i-1/2}}{\Delta x^2} (C_{i-1} - C_i)
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
|
||||
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
## Time-stamp: "Last modified 2023-01-05 17:52:55 delucia"
|
||||
## Time-stamp: "Last modified 2023-05-11 17:31:41 delucia"
|
||||
|
||||
## Brutal implementation of 2D ADI scheme
|
||||
## Square NxN grid with dx=dy=1
|
||||
@ -272,8 +272,8 @@ ADIHetDir <- function(field, dt, iter, alpha) {
|
||||
|
||||
for (it in seq(1, iter)) {
|
||||
for (i in seq(2, ny-1)) {
|
||||
Aij <- cbind(harm(alpha[i,], alpha[i-1,]), harm(alpha[i,], alpha[i+1,]))
|
||||
Bij <- cbind(harm(alpha[,i], alpha[,i-1]), harm(alpha[,i], alpha[,i+1]))
|
||||
Aij <- cbind(colMeans(rbind(alpha[i,], alpha[i-1,])), colMeans(rbind(alpha[i,], alpha[i+1,])))
|
||||
Bij <- cbind(rowMeans(cbind(alpha[,i], alpha[,i-1])), rowMeans(cbind(alpha[,i], alpha[,i+1])))
|
||||
tmpX[i,] <- SweepByRowHetDir(i, res, dt=dt, Aij, Bij)
|
||||
}
|
||||
resY <- t(tmpX)
|
||||
@ -321,22 +321,27 @@ SweepByRowHetDir <- function(i, field, dt, Aij, Bij) {
|
||||
## adi2 <- ADI(n=51, dt=10, iter=200, alpha=1E-3)
|
||||
## ref2 <- DoRef(n=51, alpha=1E-3, dt=10, iter=200)
|
||||
|
||||
n <- 5
|
||||
n <- 51
|
||||
field <- matrix(0, n, n)
|
||||
alphas <- matrix(1E-5*runif(n*n, 1,2), n, n)
|
||||
|
||||
alphas1 <- matrix(3E-5, n, 25)
|
||||
alphas2 <- matrix(1E-5, n, 26)
|
||||
|
||||
alphas <- cbind(alphas1, alphas2)
|
||||
## dim(field)
|
||||
## dim(alphas)
|
||||
## all.equal(dim(field), dim(alphas))
|
||||
|
||||
## alphas1 <- matrix(3E-5, n, 25)
|
||||
## alphas2 <- matrix(1E-5, n, 26)
|
||||
|
||||
## alphas <- cbind(alphas1, alphas2)
|
||||
|
||||
## for (i in seq(1,nrow(alphas)))
|
||||
## alphas[i,] <- seq(1E-7,1E-3, length=n)
|
||||
|
||||
#diag(alphas) <- rep(1E-2, n)
|
||||
|
||||
adih <- ADIHetDir(field=field, dt=10, iter=200, alpha=alphas)
|
||||
adi2 <- ADI(n=n, dt=10, iter=200, alpha=1E-5)
|
||||
adih <- ADIHetDir(field=field, dt=20, iter=500, alpha=alphas)
|
||||
adi2 <- ADI(n=n, dt=20, iter=500, alpha=1E-5)
|
||||
|
||||
|
||||
par(mfrow=c(1,3))
|
||||
@ -347,6 +352,17 @@ plot(adih[[length(adih)]], adi2[[length(adi2)]], pch=4, log="xy")
|
||||
abline(0,1)
|
||||
|
||||
|
||||
cchet <- lapply(adih, round, digits=6)
|
||||
cchom <- lapply(adi2, round, digits=6)
|
||||
|
||||
plot(cchet[[length(cchet)]], cchom[[length(cchom)]], pch=4, log="xy", xlim=c(1e-6,1), ylim=c(1e-6,1))
|
||||
abline(0,1)
|
||||
|
||||
cchet[[500]]
|
||||
|
||||
str(adih)
|
||||
|
||||
|
||||
sapply(adih, sum)
|
||||
sapply(adi2, sum)
|
||||
|
||||
@ -360,3 +376,108 @@ image(adih[[length(adih)]])
|
||||
points(0.5,0.5, col="red",pch=4)
|
||||
|
||||
options(width=110)
|
||||
|
||||
|
||||
FTCS_2D <- function(field, dt, iter, alpha) {
|
||||
|
||||
if (!all.equal(dim(field), dim(alpha)))
|
||||
stop("field and alpha are not matrix")
|
||||
|
||||
## now both field and alpha must be nx*ny matrices
|
||||
nx <- ncol(field)
|
||||
ny <- nrow(field)
|
||||
dx <- dy <- 1
|
||||
|
||||
## find out the center of the grid to apply conc=1
|
||||
cenx <- ceiling(nx/2)
|
||||
ceny <- ceiling(ny/2)
|
||||
field[cenx, ceny] <- 1
|
||||
|
||||
## prepare containers for computations and outputs
|
||||
tmp <- res <- field
|
||||
|
||||
cflt <- 1/max(alpha)/4
|
||||
cat(":: CFL allowable time step: ", cflt,"\n")
|
||||
|
||||
## inner iterations
|
||||
inner <- floor(dt/cflt)
|
||||
if (inner == 0) {
|
||||
## dt < cflt, no inner iterations
|
||||
inner <- 1
|
||||
tsteps <- dt
|
||||
cat(":: No inner iter. required\n")
|
||||
} else {
|
||||
tsteps <- c(rep(cflt, inner), dt-inner*cflt)
|
||||
cat(":: Number of inner iter. required: ", inner,"\n")
|
||||
}
|
||||
|
||||
|
||||
out <- vector(mode="list", length=iter)
|
||||
|
||||
for (it in seq(1, iter)) {
|
||||
cat(":: outer it: ", it)
|
||||
|
||||
for (innerit in seq_len(inner)) {
|
||||
for (i in seq(2, ny-1)) {
|
||||
for (j in seq(2, nx-1)) {
|
||||
## tmp[i,j] <- res[i,j] +
|
||||
## + tsteps[innerit]/dx/dx * (res[i+1,j]*mean(alpha[i+1,j],alpha[i,j]) -
|
||||
## res[i,j] *(mean(alpha[i+1,j],alpha[i,j])+mean(alpha[i-1,j],alpha[i,j])) +
|
||||
## res[i-1,j]*mean(alpha[i-1,j],alpha[i,j])) +
|
||||
## + tsteps[innerit]/dy/dy * (res[i,j+1]*mean(alpha[i,j+1],alpha[i,j]) -
|
||||
## res[i,j] *(mean(alpha[i,j+1],alpha[i,j])+mean(alpha[i,j-1],alpha[i,j])) +
|
||||
## res[i,j-1]*mean(alpha[i,j-1],alpha[i,j]))
|
||||
tmp[i,j] <- res[i,j] +
|
||||
+ tsteps[innerit]/dx/dx * ((res[i+1,j]-res[i,j]) * mean(alpha[i+1,j],alpha[i,j]) -
|
||||
(res[i,j]-res[i-1,j]) * mean(alpha[i-1,j],alpha[i,j])) +
|
||||
+ tsteps[innerit]/dx/dx * ((res[i,j+1]-res[i,j]) * mean(alpha[i,j+1],alpha[i,j]) -
|
||||
(res[i,j]-res[i,j-1]) * mean(alpha[i,j-1],alpha[i,j]))
|
||||
}
|
||||
}
|
||||
## swap back tmp to res for the next inner iteration
|
||||
res <- tmp
|
||||
}
|
||||
cat("- done\n")
|
||||
## at end of inner it we store
|
||||
out[[it]] <- res
|
||||
}
|
||||
|
||||
return(out)
|
||||
}
|
||||
|
||||
## testing that FTCS with homog alphas reverts to ADI/Reference sim
|
||||
n <- 51
|
||||
field <- matrix(0, n, n)
|
||||
alphas <- matrix(1E-3, n, n)
|
||||
|
||||
adi2 <- ADI(n=51, dt=100, iter=20, alpha=1E-3)
|
||||
|
||||
ref <- DoRef(n=51, alpha=1E-3, dt=100, iter=20)
|
||||
|
||||
adihet <- ADIHetDir(field=field, dt=100, iter=20, alpha=alphas)
|
||||
|
||||
ftcsh <- FTCS_2D(field=field, dt=100, iter=20, alpha=alphas)
|
||||
|
||||
|
||||
par(mfrow=c(2,4))
|
||||
image(ref, main="Reference ODE.2D")
|
||||
points(0.5,0.5, col="red",pch=4)
|
||||
image(ftcsh[[length(ftcsh)]], main="FTCS 2D")
|
||||
points(0.5,0.5, col="red",pch=4)
|
||||
image(adihet[[length(adihet)]], main="ADI Heter.")
|
||||
points(0.5,0.5, col="red",pch=4)
|
||||
image(adi2[[length(adi2)]], main="ADI Homog.", col=terrain.colors(12))
|
||||
points(0.5,0.5, col="red",pch=4)
|
||||
plot(ftcsh[[length(ftcsh)]], ref, pch=4, log="xy", xlim=c(1E-16, 1), ylim=c(1E-16, 1),
|
||||
main = "FTCS_2D vs ref", xlab="FTCS 2D", ylab="Reference")
|
||||
abline(0,1)
|
||||
plot(ftcsh[[length(ftcsh)]], adihet[[length(adihet)]], pch=4, log="xy", xlim=c(1E-16, 1), ylim=c(1E-16, 1),
|
||||
main = "FTCS_2D vs ADI Het", xlab="FTCS 2D", ylab="ADI 2D Heter.")
|
||||
abline(0,1)
|
||||
plot(ftcsh[[length(ftcsh)]], adi2[[length(adi2)]], pch=4, log="xy", xlim=c(1E-16, 1), ylim=c(1E-16, 1),
|
||||
main = "FTCS_2D vs ADI Hom", xlab="FTCS 2D", ylab="ADI 2D Hom.")
|
||||
abline(0,1)
|
||||
plot(adihet[[length(adihet)]], adi2[[length(adi2)]], pch=4, log="xy", xlim=c(1E-16, 1), ylim=c(1E-16, 1),
|
||||
main = "ADI Het vs ADI Hom", xlab="ADI Het", ylab="ADI 2D Hom.")
|
||||
abline(0,1)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user