পাঠ ৩৪ · ৫৭-এর মধ্যে · মডিউল ৭
Home / Courses / Numerical Methods / ফাইনাইট ডিফারেন্স BVP

BVP-এর জন্য ফাইনাইট ডিফারেন্স মেথড

Finite difference method for BVPs
১২ মিনিট পড়া উচ্চতর · Advanced Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কীভাবে একটি BVP-এর ডোমেইন ডিসক্রিটাইজ করে সেন্ট্রাল ডিফারেন্স দিয়ে y''-কে আনুমানিক করা হয়
  • কীভাবে এই আনুমানিকতা থেকে একটি ট্রাইডায়াগোনাল লিনিয়ার সিস্টেম গঠিত হয়, এবং কেন এটি ট্রাইডায়াগোনাল-ই হয়
  • একটি সত্যিকারের, চলমান Python ডেমো — থমাস অ্যালগরিদম দিয়ে সিস্টেম সমাধান, রেসিডুয়াল যাচাই
  • ফাইনাইট ডিফারেন্স মেথড কীভাবে O(h²) হারে কনভার্জ করে তার সত্যিকারের প্রমাণ, এবং L33-এর শুটিং মেথডের ফলাফলের সাথে ক্রস-চেক

১ · ডিসক্রিটাইজেশন — ডোমেইনকে গ্রিডে ভাগ করা

শুটিং মেথডের (L33) বিপরীতে, ফাইনাইট ডিফারেন্স মেথড ডোমেইন [a, b]-কে N+1টি সমান অংশে ভাগ করে ($h = \dfrac{b-a}{N+1}$), গ্রিড-বিন্দু $x_i = a + i h$ ($i = 0, 1, \ldots, N+1$)। প্রান্তের মান $y_0 = \alpha$ ও $y_{N+1} = \beta$ ইতিমধ্যে জানা (বাউন্ডারি কন্ডিশন) — অজানা শুধু অভ্যন্তরীণ বিন্দুগুলোর মান $y_1, y_2, \ldots, y_N$।

M5/L21-এর সেন্ট্রাল ডিফারেন্স ফর্মুলা ব্যবহার করে:

$$y_i'' \approx \frac{y_{i-1} - 2y_i + y_{i+1}}{h^2}$$

y'' = -y সমীকরণে এটি বসালে প্রতিটি অভ্যন্তরীণ বিন্দু i = 1, ..., N-এর জন্য একটি সমীকরণ পাওয়া যায়:

$$y_{i-1} + (h^2 - 2)\, y_i + y_{i+1} = 0$$

এটি Nটি অজানা (y₁ থেকে y_N) নিয়ে Nটি সমীকরণের একটি সিস্টেম — এবং প্রতিটি সমীকরণে শুধু প্রতিবেশী বিন্দুগুলোর মান জড়িত (i-1, i, i+1), তাই সিস্টেমের ম্যাট্রিক্স স্বয়ংক্রিয়ভাবে ট্রাইডায়াগোনাল — শুধু প্রধান কর্ণ ও তার ঠিক পাশের দুই কর্ণে অ-শূন্য মান।

ডিসক্রিটাইজেশন
ডোমেইনকে N+1 ভাগে ভাগ করে গ্রিড-বিন্দু তৈরি — বাউন্ডারি বিন্দু জানা, অভ্যন্তরীণ বিন্দু অজানা।
ট্রাইডায়াগোনাল সিস্টেম
প্রতিটি সমীকরণে শুধু প্রতিবেশী বিন্দু জড়িত থাকায়, ম্যাট্রিক্সে শুধু ৩টি কর্ণে অ-শূন্য মান — M3/L15-এর বিশেষ কাঠামো।
থমাস অ্যালগরিদম
ট্রাইডায়াগোনাল সিস্টেমের জন্য বিশেষায়িত সলভার — O(N) সময়ে সমাধান, সাধারণ গসিয়ান এলিমিনেশনের O(N³)-এর চেয়ে অনেক দ্রুত (M3/L15)।
সহোদর মডিউলের সাথে সংযোগ

এই লেসনটি তিনটি আগের মডিউলের টুল একসাথে ব্যবহার করে: M5/L21-এর ফাইনাইট-ডিফারেন্স ডেরিভেটিভ আনুমানিকতা, M3/L15-এর ট্রাইডায়াগোনাল (থমাস অ্যালগরিদম) সলভার, এবং M3/L10-এর লিনিয়ার সিস্টেম সমাধানের সাধারণ ধারণা। ফাইনাইট ডিফারেন্স BVP মেথড আসলে "নতুন" কিছু নয় — এটি এই তিনটি পুরনো টুলের একটি সুচিন্তিত সমন্বয়।

২ · একটি সত্যিকারের ডেমো — একই BVP, ট্রাইডায়াগোনাল সিস্টেম দিয়ে সমাধান

L33-এর একই BVP ব্যবহার করা হচ্ছে: y'' = -y, y(0) = 0, y(1) = 2, নির্ভুল সমাধান y(x) = C·sin(x), C ≈ 2.37679021। এখানে N = 9টি অভ্যন্তরীণ গ্রিড-বিন্দু (h = 0.1) ব্যবহার করে সিস্টেম গঠন ও থমাস অ্যালগরিদম দিয়ে সমাধান করা হয়েছে।

Python
import math

# একই BVP: y'' = -y on [0,1],  y(0)=0,  y(1)=2 ; exact y(x) = C*sin(x)
C_exact = 2.0 / math.sin(1.0)

N = 9            # অভ্যন্তরীণ গ্রিড-বিন্দু সংখ্যা
h = 1.0 / (N + 1)
y0, yN1 = 0.0, 2.0   # বাউন্ডারি মান

# সমীকরণ: y_{i-1} + (h^2 - 2)*y_i + y_{i+1} = 0   (i = 1..N)
a = [0.0]*(N+1); b = [0.0]*(N+1); c = [0.0]*(N+1); d = [0.0]*(N+1)
for i in range(1, N+1):
    a[i], b[i], c[i], d[i] = 1.0, -(2.0 - h*h), 1.0, 0.0

# বাউন্ডারি কন্ডিশন ডান-পাশে (rhs) ভাঁজ করা
d[1] -= a[1]*y0
d[N] -= c[N]*yN1

def thomas_solve(a, b, c, d, n):
    cp = [0.0]*(n+1); dp = [0.0]*(n+1)
    cp[1] = c[1]/b[1]; dp[1] = d[1]/b[1]
    for i in range(2, n+1):
        m = b[i] - a[i]*cp[i-1]
        cp[i] = c[i]/m if i < n else 0.0
        dp[i] = (d[i] - a[i]*dp[i-1]) / m
    x = [0.0]*(n+1)
    x[n] = dp[n]
    for i in range(n-1, 0, -1):
        x[i] = dp[i] - cp[i]*x[i+1]
    return x

y = thomas_solve(a, b, c, d, N)
xs = [i*h for i in range(N+2)]
ys = [y0] + [y[i] for i in range(1, N+1)] + [yN1]

print(f"{'x':>6} {'FD y(x)':>14} {'নির্ভুল C*sin(x)':>18} {'|এরর|':>12}")
for i in range(N+2):
    exact = C_exact * math.sin(xs[i])
    print(f"{xs[i]:6.2f} {ys[i]:14.8f} {exact:18.8f} {abs(ys[i]-exact):12.2e}")

# রেসিডুয়াল যাচাই: মূল (আন-ফোল্ডেড) সমীকরণে ফিরে বসিয়ে দেখা
max_res = max(abs(ys[i-1] + b[i]*ys[i] + ys[i+1]) for i in range(1, N+1))
print()
print("সর্বোচ্চ |রেসিডুয়াল| (হওয়া উচিত ~0):", max_res)

# কনভারজেন্স-অর্ডার যাচাই: N দ্বিগুণ করলে এরর কীভাবে কমে (x=0.5-এ)
print()
print("গ্রিড সূক্ষ্ম করলে x=0.5-এ এরর (O(h^2) কনভারজেন্স যাচাই):")
for Ntest in [9, 19, 39]:
    h2 = 1.0/(Ntest+1)
    a2=[0.0]*(Ntest+1); b2=[0.0]*(Ntest+1); c2=[0.0]*(Ntest+1); d2=[0.0]*(Ntest+1)
    for i in range(1, Ntest+1):
        a2[i], b2[i], c2[i], d2[i] = 1.0, -(2.0-h2*h2), 1.0, 0.0
    d2[Ntest] -= c2[Ntest]*yN1
    y2 = thomas_solve(a2, b2, c2, d2, Ntest)
    idx = round(0.5/h2)
    y_at_half = y2[idx]
    err = abs(y_at_half - C_exact*math.sin(idx*h2))
    print(f"N={Ntest:3d}  h={h2:.5f}  y(0.5)≈{y_at_half:.8f}  এরর={err:.3e}")

    
মাত্র N=9 অভ্যন্তরীণ বিন্দু (h=0.1) দিয়ে x=0.5-এ পাওয়া যায় y ≈ 1.13962380, নির্ভুল মান 1.13949393-এর তুলনায় এরর ১.৩০ × ১০⁻⁴। রেসিডুয়াল চেক দেখায় সমাধানটি মূল সিস্টেমকে প্রায় নিখুঁতভাবে সিদ্ধ করে (~10⁻¹⁶, ফ্লোটিং-পয়েন্ট নির্ভুলতার সীমা)। গ্রিড দ্বিগুণ সূক্ষ্ম করলে (N=9→19→39) এরর যায় 1.30×10⁻⁴ → 3.24×10⁻⁵ → 8.11×10⁻⁶ — প্রতিবার h অর্ধেক হলে এরর প্রায় চার গুণ কমছে, যা এই সেন্ট্রাল-ডিফারেন্স স্কিমের তাত্ত্বিক O(h²) কনভারজেন্স অর্ডারের সাথে সরাসরি মেলে। আর L33-এর শুটিং মেথড (RK4, খুব ছোট ধাপ) দিয়ে একই বিন্দুতে পাওয়া গিয়েছিল y(0.5) ≈ 1.13949431 — মাত্র N=9-এর মোটা গ্রিডের ফাইনাইট ডিফারেন্স ফলাফলের সাথে পার্থক্য মাত্র 1.29×10⁻⁴, যা ফাইনাইট ডিফারেন্সের নিজস্ব 1.30×10⁻⁴ এররের সাথে প্রায় হুবহু মেলে — দুটি সম্পূর্ণ ভিন্ন পদ্ধতি একে অপরকে সত্যিকারভাবে যাচাই করছে।
শুটিং বনাম ফাইনাইট ডিফারেন্স — কখন কোনটা

শুটিং মেথড (L33) সহজে বাস্তবায়নযোগ্য এবং M6-এর IVP সলভার সরাসরি পুনর্ব্যবহার করে, কিন্তু নন-লিনিয়ার সমস্যায় অস্থিতিশীল হতে পারে। ফাইনাইট ডিফারেন্স মেথড পুরো সিস্টেম একসাথে সমাধান করে বলে বেশি নির্ভরযোগ্য (বিশেষত কঠিন/স্টিফ BVP-তে), কিন্তু একটি বড় লিনিয়ার সিস্টেম (বা নন-লিনিয়ার হলে, একটি নন-লিনিয়ার সিস্টেম) সমাধানের প্রয়োজন হয়। বাস্তব ইঞ্জিনিয়ারিং সফটওয়্যারে (কাঠামোগত বিশ্লেষণ, তাপ স্থানান্তর) ফাইনাইট ডিফারেন্স/এলিমেন্ট মেথড অনেক বেশি প্রচলিত, ঠিক এই স্কেলেবিলিটির কারণে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ ফাইনাইট ডিফারেন্স সিস্টেমের প্রতিটি সমীকরণে শুধু y_{i-1}, y_i, y_{i+1} জড়িত — y_{i-2} বা y_{i+2} নয়। এটি কেন ম্যাট্রিক্সকে ট্রাইডায়াগোনাল করে তোলে, এবং এটি কেন থমাস অ্যালগরিদমকে O(N) সময়ে চলতে দেয়?

ম্যাট্রিক্সের সারি i-তে শুধু কলাম i-1, i, i+1-এ অ-শূন্য মান থাকে — বাকি সব কলামে শূন্য। এই কাঠামোই "ট্রাইডায়াগোনাল"-এর সংজ্ঞা (M3/L15)। যেহেতু বেশিরভাগ এন্ট্রি আগে থেকেই শূন্য জানা, থমাস অ্যালগরিদম শুধু অ-শূন্য এন্ট্রিগুলো নিয়ে কাজ করে — প্রতিটি সারিতে ধ্রুবক সংখ্যক অপারেশন, তাই মোট N সারিতে O(N) সময়। সাধারণ গসিয়ান এলিমিনেশন (M3/L10) এই বিশেষ কাঠামো ব্যবহার করে না, তাই O(N³) সময় নেয়।

প্র ০২ রেসিডুয়াল চেকে ~10⁻¹⁶ মাত্রার মান পাওয়া গেছে, কিন্তু নির্ভুল সমাধানের বিপরীতে এরর ~10⁻⁴ মাত্রার। এই দুটি সংখ্যা এত ভিন্ন কেন — একটি প্রায় শূন্য, আরেকটি নয়?

রেসিডুয়াল ~10⁻¹⁶ শুধু বলে যে থমাস অ্যালগরিদম ডিসক্রিটাইজড সমীকরণ-কে (আনুমানিক সিস্টেম) প্রায় নিখুঁতভাবে সমাধান করেছে — এটি লিনিয়ার-অ্যালজেব্রার নির্ভুলতা। কিন্তু ~10⁻⁴ এরর হলো ডিসক্রিটাইজেশন এরর — সেন্ট্রাল ডিফারেন্স ফর্মুলা নিজেই y''-এর একটি আনুমানিকতা মাত্র, প্রকৃত মান নয় (M5/L21-এ ট্রাংকেশন এরর হিসেবে ব্যাখ্যা করা হয়েছে)। এই দুটি সম্পূর্ণ ভিন্ন এরর উৎস — একটি সমাধান-পদ্ধতির নির্ভুলতা, অন্যটি মডেলের নিজস্ব আনুমানিকতা।

প্র ০৩ শুটিং মেথড ও ফাইনাইট ডিফারেন্স মেথড সম্পূর্ণ ভিন্ন অ্যালগরিদমিক পথ নিয়েছে, কিন্তু x=0.5-এ প্রায় একই উত্তরে পৌঁছেছে। এই ধরনের "স্বাধীন যাচাই" (independent verification) কেন একটি সংখ্যাসূচক ফলাফলের উপর আস্থা বাড়ায়?

দুটি ভিন্ন পদ্ধতি — ভিন্ন গাণিতিক ভিত্তি, ভিন্ন এরর উৎস, ভিন্ন কোড — যদি প্রায় একই উত্তরে পৌঁছায়, তাহলে সেটি এক পদ্ধতির একটি সূক্ষ্ম বাগ বা মৌলিক ভুল থাকার সম্ভাবনা কমিয়ে দেয় (দুটি পদ্ধতিতেই ঠিক একই বাগ থাকার সম্ভাবনা কম)। এটি বাস্তব ইঞ্জিনিয়ারিং সিমুলেশনের একটি প্রমিত অনুশীলন — একটি একক সংখ্যাসূচক ফলাফলে আস্থা রাখার আগে, সম্ভব হলে একটি স্বতন্ত্র পদ্ধতি দিয়ে ক্রস-চেক করা (M11/L50-এ ফরওয়ার্ড/ব্যাকওয়ার্ড এরর অ্যানালাইসিসের সাথে সম্পর্কিত ধারণা)।

অনুশীলন

  1. চিন্তা করুন: কনভারজেন্স-অর্ডার আউটপুটে N=9→19 ও N=19→39-এ এরর প্রতিবার প্রায় চার গুণ কমে। যদি N আরও বাড়িয়ে N=79 করা হয় (h আবার অর্ধেক), এরর মোটামুটি কত হবে বলে আপনার ধারণা?

    O(h²) কনভারজেন্স মানে h অর্ধেক হলে এরর প্রায় চার ভাগের এক ভাগ হয়। N=39-এ এরর ছিল 8.106×10⁻⁶, তাই N=79-এ এরর মোটামুটি 8.106×10⁻⁶ / 4 ≈ 2.0×10⁻⁶ হওয়ার কথা — কোড সেলে Ntest তালিকায় 79 যোগ করে চালিয়ে যাচাই করা যায়।

  2. পরীক্ষা করুন: কোড সেলে yN1 = 2.0-কে yN1 = 0.0-এ পরিবর্তন করে Run চাপুন (তাহলে y(0)=0, y(1)=0 — একটি ভিন্ন BVP)। ফলাফল y সব বিন্দুতে কী হয়, এবং এটি কেন y''=-y-এর প্রেক্ষাপটে সংগতিপূর্ণ?

    y(0)=0 ও y(1)=0-এ পরিবর্তন করলে ফাইনাইট ডিফারেন্স সমাধান সব গ্রিড-বিন্দুতে প্রায় 0 দেয়, কারণ y(x)=0 (সব জায়গায়) হলো y''=-y, y(0)=0, y(1)=0-এর একটি বৈধ (ট্রিভিয়াল) সমাধান — বাস্তবে এই নির্দিষ্ট সমস্যার অসীম সংখ্যক সমাধান থাকতে পারে যদি sin(1)=0 হতো (এখানে হয় না, তাই সমাধান অনন্য), কিন্তু ট্রিভিয়াল y≡0 সবসময় একটি বৈধ সমাধান। এটি দেখায় বাউন্ডারি কন্ডিশনের ছোট পরিবর্তনও সমাধানকে গুণগতভাবে বদলে দিতে পারে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
বাউন্ডারি ভ্যালু প্রবলেম — শুটিং মেথড