¿Cómo discretizar la ecuación de advección usando el método de Crank-Nicolson?

8

La ecuación de advección necesita ser discretizada para ser utilizada para el método de Crank-Nicolson. ¿Alguien puede mostrarme cómo hacer eso?

pandoragami
fuente
1
Bienvenido a SciComp! El alcance de su pregunta se ajusta muy bien a este sitio. Sin embargo, para obtener buenas respuestas, debe ser más específico. Indique, en particular, qué no comprende. Su código se ve bien estructurado y documentado, pero para responder a su pregunta, tal vez lo haga un fragmento de código más pequeño.
enero
Podría simplificar su depuración si usa un caso de prueba en el que su vector de entrada tiene, digamos, 5 elementos, y pasa por el código con un depurador como gdb y ddd. Hacerlo podría ayudar a reducir la fuente del error. Creo que la mayoría de las preguntas de depuración de código no funcionan muy bien aquí porque la mayoría del trabajo implica averiguar dónde está el error en primer lugar. Una vez que lo encuentre, la explicación es con frecuencia (pero no siempre) sencilla. ¿Puede ejecutar una prueba unitaria para determinar si hay algún error en Tridiagonal que pueda estar causando este comportamiento?
Geoff Oxberry
Eche un vistazo a este ejemplo en la entrada de Wikipedia sobre el método de Crank-Nicolson. Si establece y en cero, se convertirá en un problema de advección simple. Queda por incorporar las condiciones de contorno ...kreX
enero
Lo siento chicos, pero el método Crank-Nicolson es totalmente inapropiado para un problema de advección. La estabilidad y la precisión de la aproximación diferencial local, lamentablemente, no garantizan la coherencia. Obtendrá la solución de un problema diferente. En algunos casos triviales, puede tener suerte, pero la ecuación de advección es en general implacable. Consulte los libros de texto de análisis numérico. El esquema de Crank-Nicolson nunca se usa. La gente todavía tiene que adoptarlo en algunos problemas de ingeniería, debido a la estabilidad, pero allí tienen que controlar la solución a medida que evoluciona y tienen heurística para probar erro

Respuestas:

19

Comenzando con la ecuación de advección es de forma conservadora,

tut=-(vtu)X+s(X,t)

El método de Crank-Nicolson consiste en una diferencia centrada promediada en el tiempo.

tujnorte+1-tujnorteΔt=-v[1-β2ΔX(tuj+1norte-tuj-1norte)+β2ΔX(tuj+1norte+1-tuj-1norte+1)]+s(X,t)

Con respecto a la notación, los subíndices son para puntos en el espacio, y los superíndices son para puntos en el tiempo.

Los puntos en están en el futuro: son incógnitas. Ahora tenemos que reorganizar la ecuación anterior para que todos los conocimientos estén en la derecha y las incógnitas estén en la derecha.norte+1

Haciendo la sustitución,

r=v2ΔtΔX

da,

-βrϕj-1norte+1+ϕjnorte+1+βrϕj+1norte+1=(1-β)rϕj-1norte+ϕjnorte-(1-β)rϕj+1norte

Esta es la ecuación de advección discretizada utilizando el método de Crank-Nicolson. Puedes escribirlo como una ecuación matricial,

(1βr0 0-βr1βr-βr1βr0 0-βr1)(tu1norte+1tu2norte+1tuJ-1norte+1tuJnorte+1)=(1-(1-β)r0 0(1-β)r1-(1-β)r(1-β)r1-(1-β)r0 0(1-β)r1)(tu1nortetu2nortetuJ-1nortetuJnorte)
Configurar le dará una integración trapezoidal a tiempo, por lo que para Crank-Nicolson esto es lo que desea.β=1/ /2

Algunas palabras de advertencia. Esta es la solución básica que deseaba, pero deberá incluir algún tipo de condición límite para un problema bien planteado. Además, Crank-Nicolson no es necesariamente el mejor método para la ecuación de advección. Es de segundo orden preciso e incondicionalmente estable , lo cual es fantástico. Sin embargo, generará (como con todas las plantillas de diferencia centrada) una oscilación espuria si tiene soluciones puntuales muy agudas o condiciones iniciales.

Escribí el siguiente código para usted en Python, debería ayudarlo a comenzar. El código resuelve la ecuación de advección para una curva gaussiana inicial que se mueve hacia la derecha con velocidad constante.

Curva gaussiana que se mueve hacia la derecha con velocidad constante

from __future__ import division
from scipy.sparse import spdiags
from scipy.sparse.linalg import spsolve
import numpy as np
import pylab

def make_advection_matrices(z, r):
    """Return matrices A and M for advection equations"""
    ones = np.ones(len(z))
    A = spdiags( [-beta*r, ones, beta*r], (-1,0,1), len(z), len(z) )
    M = spdiags( [(1-beta) * r, ones, -(1-beta) * r], (-1,0,1), len(z), len(z) )
    return A.tocsr(), M.tocsr()

def plot_iteration(z, u, iteration):
    """Plot the solver progress"""
    pylab.plot(z, u, label="Iteration %d" % iteration)

# Set up basic constants
beta = 0.5
J = 200 # total number of mesh points
z = np.linspace(-10,10,J) # vertices
dz = abs(z[1]-z[0]) # space step
dt = 0.2    # time step
v = 2 * np.ones(len(z)) # velocity field (constant)
r = v / 2 * dt / dz

# Initial conditions (peak function)
gaussian = lambda z, height, position, hwhm: height * np.exp(-np.log(2) * ((z - position)/hwhm)**2)
u_init = gaussian(z, 1, -3, 2)

A, M = make_advection_matrices(z, r)
u = u_init
for i in range(10):
    u = spsolve(A, M * u)
    plot_iteration(z, u, i)

pylab.legend()
pylab.show()
boyfarrell
fuente
3
En realidad, también vi tu pregunta anterior, pero era tan general que no pude responder (cuando publicaste una página de código). En mi experiencia, cuando haces una buena pregunta en este sitio, la gente es muy útil. ¡Buen viaje!
boyfarrell
Sólo bromeo.
pandoragami
@boyfarrel ¿Hay alguna posibilidad de que tenga una versión C ++ / C de esto? Está bien si no. No uso mucho matlab y no tengo ganas de aprenderlo. Incluso fortran sería mejor.
pandoragami
2
<comentarios inapropiados eliminados>
Paul