Làm thế nào để phân biệt phương trình thăng tiến bằng phương pháp Crank-Nicolson?


8

Phương trình tiến lên cần được rời rạc để được sử dụng cho phương pháp Crank-Nicolson. Ai đó có thể chỉ cho tôi làm thế nào để làm điều đó?


1
Chào mừng đến với SciComp! Phạm vi câu hỏi của bạn rất phù hợp với trang web này. Để có được câu trả lời tốt, tuy nhiên, bạn nên cụ thể hơn. Vui lòng cho biết, những gì cụ thể bạn không hiểu. Mã của bạn trông có cấu trúc và tài liệu tốt, nhưng để trả lời câu hỏi của bạn, có thể một đoạn mã nhỏ hơn sẽ làm được.
Jan

Nó có thể làm cho việc gỡ lỗi của bạn đơn giản hơn nếu bạn sử dụng một trường hợp thử nghiệm trong đó vectơ đầu vào của bạn có 5 phần tử và bạn bước qua mã với trình gỡ lỗi như gdb và ddd. Làm như vậy có thể giúp thu hẹp nguồn lỗi. Tôi nghĩ rằng hầu hết các câu hỏi gỡ lỗi mã không hoạt động tốt ở đây vì phần lớn công việc liên quan đến việc tìm ra lỗi ở đâu ngay từ đầu. Một khi bạn tìm thấy nó, lời giải thích thường xuyên (nhưng không phải luôn luôn) đơn giản. Bạn có thể chạy thử nghiệm đơn vị để tìm hiểu xem có bất kỳ lỗi nào trong Tridia chéo có thể gây ra hành vi này không?
Geoff Oxberry

Hãy xem ví dụ này trong mục Wikipedia về phương pháp Crank-Nicolson. Nếu bạn đặt và thành 0, nó sẽ biến thành một vấn đề tiến bộ rõ ràng. Nó vẫn còn để kết hợp các điều kiện biên ...D xkDx
Jan

Xin lỗi các bạn, nhưng phương pháp Crank-Nicolson hoàn toàn không phù hợp cho một vấn đề tiến bộ. Tính ổn định và độ chính xác của xấp xỉ vi phân cục bộ không may không đảm bảo tính nhất quán. Bạn sẽ nhận được giải pháp của một vấn đề khác. Trong một số trường hợp tầm thường, bạn có thể gặp may mắn nhưng phương trình thăng tiến nói chung là không tha thứ. Kiểm tra sách giáo khoa phân tích số. Sơ đồ Crank-Nicolson không bao giờ được sử dụng. Mọi người vẫn phải áp dụng nó trong một số vấn đề kỹ thuật, vì tính ổn định, nhưng ở đó họ phải kiểm soát giải pháp khi nó phát triển và có kinh nghiệm để kiểm tra erro

Câu trả lời:


19

Bắt đầu với phương trình thăng tiến là hình thức bảo thủ,

ut=(vu)x+s(x,t)

Phương pháp Crank-Nicolson bao gồm thời gian trung bình chênh lệch trung tâm.

ujn+1ujnΔt=v[1β2Δx(uj+1nuj1n)+β2Δx(uj+1n+1uj1n+1)]+s(x,t)

Về ký hiệu, kí hiệu là cho điểm trong không gian, và superscript là cho điểm trong thời gian.

Các điểm tại là trong tương lai: chúng là ẩn số. Bây giờ chúng ta cần sắp xếp lại các phương trình trên để tất cả các điều đã biết đều nằm trên rhs và ẩn số nằm trên lhs.n+1

Thay thế,

r=v2ΔtΔx

cho

βrϕj1n+1+ϕjn+1+βrϕj+1n+1=(1β)rϕj1n+ϕjn(1β)rϕj+1n

Đây là phương trình thăng tiến được sử dụng bằng phương pháp Crank-Nicolson. Bạn có thể viết nó như một phương trình ma trận,

(1βr0βr1βrβr1βr0βr1)(u1n+1u2n+1uJ1n+1uJn+1)=(1(1β)r0(1β)r1(1β)r(1β)r1(1β)r0(1β)r1)(u1nu2nuJ1nuJn)
Cài đặt sẽ giúp bạn tích hợp hình thang theo thời gian, vì vậy đối với Crank-Nicolson, đây là điều bạn muốn.β=1/2

Một vài lời cảnh báo. Đây là giải pháp cơ bản mà bạn muốn, nhưng bạn sẽ cần đưa vào một số loại điều kiện biên cho một vấn đề được đặt ra. Ngoài ra, Crank-Nicolson không nhất thiết là phương pháp tốt nhất cho phương trình thăng tiến. Đó là thứ hai chính xác và ổn định vô điều kiện , đó là tuyệt vời. Tuy nhiên, nó sẽ tạo ra (như với tất cả các bút chì khác biệt tập trung) dao động giả nếu bạn có các giải pháp cực đại rất sắc nét hoặc các điều kiện ban đầu.

Tôi đã viết đoạn mã sau cho bạn bằng Python, nó sẽ giúp bạn bắt đầu. Mã giải phương trình thăng tiến cho một đường cong Gaussian ban đầu di chuyển sang phải với vận tốc không đổi.

Đường cong Gaussian di chuyển sang phải với vận tốc không đổi

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()

3
Thật ra tôi cũng thấy câu hỏi trước đó của bạn nhưng nó quá chung chung nên tôi không thể trả lời (khi bạn đăng một trang mã). Theo kinh nghiệm của tôi, khi bạn đặt câu hỏi hay trên trang này, mọi người rất hữu ích. Bon hành trình!
boyfarrell

Tôi chỉ đua thôi.
pandoragami

@boyfarrel Có bất kỳ cơ hội nào bạn có phiên bản C ++ / C này không. Nó ổn nếu không có. Tôi không sử dụng matlab nhiều và tôi không muốn học nó. Ngay cả fortran sẽ tốt hơn.
pandoragami

2
<đã xóa các bình luận không phù hợp>
Paul
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.