/// <summary> /// Решение задачи Штурма-Лиувилля /// </summary> /// <param name="g">Функция внутри второй производной</param> /// <param name="h">Функция при первой производной</param> /// <param name="s">Функция при искомой функции</param> /// <param name="f">Свободная функция</param> /// <param name="a">Начало отрезка</param> /// <param name="b">Конец отрезка</param> /// <param name="N">Число шагов</param> /// <param name="A"></param> /// <param name="B"></param> /// <param name="C"></param> /// <param name="D"></param> /// <param name="A1"></param> /// <param name="B1"></param> /// <param name="C1"></param> /// <param name="D1"></param> /// <returns></returns> public static NetFunc SchLiuQu(Func <double, double> g, Func <double, double> h, Func <double, double> s, Func <double, double> f, out double nevaska, double a = 0, double b = 10, int N = 50, double A = 1, double B = 1, double D = 1, double A1 = 1, double B1 = 1, double D1 = 1, bool firstkind = true) { double[] hn = new double[N + 1], fn = new double[N + 1], sn = new double[N + 1], tn = new double[N + 1], an = new double[N + 1], bn = new double[N + 1], cn = new double[N + 1], dn = new double[N + 1]; double t = (b - a) / N; for (int i = 0; i < N + 1; i++) { double arg = a + i * t; tn[i] = arg; hn[i] = h(arg); fn[i] = f(arg); sn[i] = s(arg); an[i] = (g(arg - t / 2) / t - hn[i] / 2) / t; cn[i] = (g(arg + t / 2) / t + hn[i] / 2) / t; bn[i] = an[i] + cn[i] - sn[i]; //поставил sn вместо hn //bn[i] = (g(arg + t / 2) - g(arg - t / 2)) / t / t - sn[i]; dn[i] = fn[i]; } double k1 = 0, k2 = 0; if (firstkind) { bn[0] = A / t - B; cn[0] = A / t; dn[0] = D; an[N] = -A1 / t; bn[N] = -A1 / t - B1; dn[N] = D1; } else { bn[0] = 3 * A / 2 / t - B; cn[0] = 2 * A / t; k1 = -A / 2 / t; bn[N] = -3 * A1 / 2 / t - B1; an[N] = -2 * A1 / t; k2 = A1 / 2 / t; } dn[0] = D; dn[N] = D1; SLAU S = new SLAU(N + 1); S.A[0, 0] = -bn[0]; S.A[0, 1] = cn[0]; S.A[0, 2] = k1; S.A[N, N - 1] = an[N]; S.A[N, N - 2] = k2; S.A[N, N] = -bn[N]; S.b[0] = dn[0]; S.b[N] = dn[N]; for (int i = 1; i < N; i++) { S.A[i, 0 + i - 1] = an[i]; S.A[i, 1 + i - 1] = -bn[i]; S.A[i, 2 + i - 1] = cn[i]; S.b[i] = dn[i]; } S.Show(); "".Show(); double c1 = S.A[0, 2] / S.A[1, 2], c2 = S.A[N, N - 2] / S.A[N - 1, N - 2]; for (int i = 0; i < 3; i++) { S.A[0, i] -= S.A[1, i] * c1; S.A[N, N - i] -= S.A[N - 1, N - i] * c2; } S.b[0] -= S.b[1] * c1; S.b[N] -= S.b[N - 1] * c2; //S.Show(); "".Show(); S.ProRace(); S.Show(); nevaska = S.Nevaska; NetFunc res = new NetFunc(); for (int i = 0; i < N + 1; i++) { res.Add(new Point(tn[i], S.x[i])); } return(res); }
/// <summary> /// Решение уравнения теплопроводности явной либо неявной схемой /// </summary> /// <param name="f">Свободная фунция из уравнения</param> /// <param name="f1">Функция из первого краевого условия</param> /// <param name="f2">Функция из второго краевого условия</param> /// <param name="u0">Функция из начальных условий</param> /// <param name="u">Искомая функция (нужна для вычисления точности самого решения)</param> /// <param name="a">Коэффициент при второй производной</param> /// <param name="A1"></param> /// <param name="B1"></param> /// <param name="A2"></param> /// <param name="B2"></param> /// <param name="x0">Начало отрезка по пространству</param> /// <param name="X">Конец отрезка по пространству</param> /// <param name="t0">Начало отрезка по времени</param> /// <param name="T">Конец отрезка по времени</param> /// <param name="xcount">Число шагов по пространству</param> /// <param name="tcount">Число шагов по времени</param> /// <param name="accuracy">Выводимая точность</param> /// <param name="explict">Использовать явную схему либо нет</param> /// <returns></returns> public static List <NetFunc> TU(DRealFunc f, Func <double, double> f1, Func <double, double> f2, Func <double, double> u0, DRealFunc u, double a, double A1, double B1, double A2, double B2, double x0, double X, double t0, double T, int xcount, int tcount, out double accuracy, bool explict = true, bool thirdkind = true) { List <NetFunc> res = new List <NetFunc>(); double h = (X - x0) / (xcount - 1); double tau = (T - t0) / (tcount - 1); double[] x = new double[xcount], t = new double[tcount]; double[] value = new double[xcount]; for (int i = 0; i < xcount; i++) { x[i] = x0 + i * h; } for (int i = 0; i < tcount; i++) { t[i] = t0 + i * tau; } for (int i = 0; i < xcount; i++) { value[i] = u0(x[i]); } res.Add(new NetFunc(x, value)); double th = tau / h / h; double h1 = A1 + h * B1, h2 = A2 + h * B2; //(h1*h1.Reverse()).Show(); if (explict) { for (int i = 1; i < tcount; i++) { for (int j = 1; j < xcount - 1; j++) { value[j] = res[i - 1].Values[j] + a * th * (res[i - 1].Values[j - 1] - 2 * res[i - 1].Values[j] + res[i - 1].Values[j + 1]) + tau * f(t[i /*-1*/], x[j]); } if (thirdkind) { value[0] = (A1 * value[1] + h * f1(t[i])) / h1; value[xcount - 1] = (A2 * value[xcount - 2] + h * f2(t[i])) / h2; } else { value[0] = f1(t[i]) / B1; value[xcount - 1] = f2(t[i]) / B2; } res.Add(new NetFunc(x, value)); //new Vectors (res.Last().Values).Show(); } } else { SLAU s = new SLAU(xcount); for (int i = 1; i < tcount; i++) { if (thirdkind) { s.A[0, 0] = h1; s.A[0, 1] = -A1; s.b[0] = h * f1(t[i]); s.A[xcount - 1, xcount - 1] = h2; s.A[xcount - 1, xcount - 2] = -A2; s.b[xcount - 1] = h * f2(t[i]); } else { s.A[0, 0] = B1; s.b[0] = f1(t[i]); s.A[xcount - 1, xcount - 1] = B2; s.b[xcount - 1] = f2(t[i]); } for (int j = 1; j < xcount - 1; j++) { s.A[j, j - 2 + 1] = -a * th; s.A[j, j - 2 + 2] = a * 2 * th + 1; s.A[j, j - 2 + 3] = -a * th; s.b[j] = res[i - 1].Values[j - 2 + 2] + tau * f(t[i /*-1*/], x[j]); } s.ProRace(); // "".Show(); //s.Show(); value = s.x; res.Add(new NetFunc(x, value)); } } accuracy = 0; double[,] ac = new double[tcount, xcount]; for (int i = 0; i < t.Length; i++) { for (int j = 0; j < x.Length; j++) { ac[i, j] = Math.Abs(u(t[i], x[j]) - res[i].Values[j]); } } accuracy = new Matrix(ac).Max; return(res); }
/// <summary> /// Интерполяция кубическими сплайнами дефекта 1 по массиву точек /// </summary> /// <param name="P"></param> /// <param name="a">Граничное условие в начале отрезка</param> /// <param name="b">Граничное условие в конце отрезка</param> /// <param name="is0outcut">Должен ли сплайн равняться 0 вне отрезка задания</param> /// <returns></returns> public static Func <double, double> CubeSpline(Point[] P, double a = 0, double b = 0, bool is0outcut = false) { int n = P.Length - 1;//записать в новую переменную для облегчения double[] h = new double[n + 1]; double[] y = new double[n + 1]; hmax = P[1].x - P[0].x; for (int i = 1; i <= n; i++) { h[i] = P[i].x - P[i - 1].x;//Заполнение массива длин отрезков if (h[i] > hmax) { hmax = h[i]; } y[i] = P[i].y - P[i - 1].y; } //создание, заполнение и решение системы с трёхдиагональной матрицей SLAU S = new SLAU(n + 1); S.A[0, 0] = -4.0 / h[1]; S.A[0, 1] = -2.0 / h[1]; S.b[0] = -6.0 * y[1] / (h[1] * h[1]) + a; S.A[n, n - 1] = 2.0 / h[n]; S.A[n, n] = 4.0 / h[n]; S.b[n] = 6.0 * y[n] / (h[n] * h[n]) + b; for (int i = 1; i <= n - 1; i++) { S.A[i, i - 1] = 1.0 / h[i]; S.A[i, i] = 2 * (1.0 / h[i] + 1.0 / h[i + 1]); S.A[i, i + 1] = 1.0 / h[i + 1]; S.b[i] = 3 * (y[i] / h[i] / h[i] + y[i + 1] / h[i + 1] / h[i + 1]); } //S.b[0] = a; //S.b[n] = b; S.ProRace(); syst = S; //S.Show(); //создание и заполнение массива полиномов Polynom[] mas = new Polynom[n + 1]; Polynom.SplinePol = new string[n]; for (int i = 1; i <= n; i++) { Polynom p1, p2, p3, p4; p1 = (new Polynom(1, P[i].x, P[i].x)) * (2 * new Polynom(P[i - 1].x) + h[i]) / Math.Pow(h[i], 3) * P[i - 1].y; p2 = (new Polynom(1, P[i - 1].x, P[i - 1].x)) * (-2 * new Polynom(P[i].x) + h[i]) / Math.Pow(h[i], 3) * P[i].y; p3 = (new Polynom(1, P[i].x, P[i].x)) * (new Polynom(P[i - 1].x)) / Math.Pow(h[i], 2) * S.x[i - 1]; p4 = (new Polynom(1, P[i - 1].x, P[i - 1].x)) * (new Polynom(P[i].x)) / Math.Pow(h[i], 2) * S.x[i]; mas[i] = p1 + p2 + p3 + p4; SplinePol[i - 1] = String.Format("[{0};{1}]: {2}", P[i - 1].x, P[i].x, mas[i].ToString()); //mas[i].Show(); } //mas[0] = mas[1];mas[n + 1] = mas[n]; //создание производных сплайна Polynom[] mas1 = new Polynom[n + 1], mas2 = new Polynom[n + 1]; for (int i = 1; i <= n; i++) { mas1[i] = mas[i] | 1; mas2[i] = mas1[i] | 1; } DSpline = (double x) => { if (x <= P[1].x) { return(mas1[1].Value(x)); } if (x >= P[n].x) { return(mas1[n].Value(x)); } int i = 1; while (x > P[i].x) { i++; } return(mas1[i].Value(x)); }; D2Spline = (double x) => { if (x <= P[1].x) { return(mas2[1].Value(x)); } if (x >= P[n].x) { return(mas2[n].Value(x)); } int i = 1; while (x > P[i].x) { i++; } return(mas2[i].Value(x)); }; //создание общей функции и вывод return((double x) => { if (x <= P[1].x) { return (is0outcut) ? 0 : mas[1].Value(x); } if (x >= P[n].x) { return (is0outcut) ? 0 : mas[n].Value(x); } int i = 1; //while (x > P[i].x) i++; int i1 = 1, i2 = n; //реализация бинарного поиска while (i2 - i1 != 1) { int tmp = Expendator.Average(i1, i2); if (x > P[tmp].x) { i1 = tmp; } else { i2 = tmp; } } i = i2; return mas[i].Value(x); }); }