/// <summary> /// Решение системы ОДУ первого порядка /// </summary> /// <param name="f">Свободная функция переменных u и x, где u - искомая функция</param> /// <param name="begin">Начальный аргумент по задаче Коши</param> /// <param name="end">Конечный аргумент</param> /// <param name="step">Шаг интегрирования</param> /// <param name="M">Метод поиска решения</param> /// <param name="begval">Значение функции при начальном аргументе</param> /// <param name="eps">Допустимый уровень расчётных погрешностей</param> /// <returns></returns> public static VectorNetFunc ODUsearch(VRealFunc f, Vectors begval, double begin = 0, double end = 10, double step = 0.01, Method M = Method.E1, double eps = 0.0001, bool controllingstep = false) { //$"Вызов функции от вектора {begval}".Show(); double thisstep = step; VectorNetFunc res = new VectorNetFunc(); res.Add(new PointV(begin, begval)); step *= Math.Sign(end - begin); Matrix A; switch (M) { case Method.E1: A = E1; break; case Method.E2: A = E2; break; case Method.H: A = H; break; case Method.RK3: A = RK3; break; case Method.RK4: A = Rk4; break; case Method.P38: A = P38; break; case Method.F: A = F; break; default: A = C; break; } int r = A.RowCount - 1; if (A.RowCount != A.ColCount) { r--; } while (begin < /*=*/ end) { Vectors u = res.Last().Item2; double t = res.Last().Item1; Vectors[] k = new Vectors[r]; Vectors tmp = new Vectors(u.Deg), tmpp = new Vectors(u.Deg); int stepchange = 0; //double[] h2 = new double[2]; //Get2Tmp(ref tmp, ref tmpp, step/2, A, k, f, u, t, r); //double uh1 = u + tmp * step/2; //Get2Tmp(ref tmp, ref tmpp, step / 2, A, k, f, uh1, t+step/2, r); //double uh2 = uh1 + tmp * step/2; Get2Tmp(ref tmp, ref tmpp, step, A, k, f, u, t, r); Vectors val1 = u + step * tmp, val2 = u + step * tmpp; double R = 0.2 * (val1 - val2).EuqlidNorm; if (controllingstep && stepchange <= MaxStepChange) { Get2Tmp(ref tmp, ref tmpp, step / 2, A, k, f, u, t, r); Vectors uh1 = u + tmp * step / 2; Get2Tmp(ref tmp, ref tmpp, step / 2, A, k, f, uh1, t + step / 2, r); Vectors uh2 = uh1 + tmp * step / 2; int p; switch (M) { case Method.E1: p = 1; break; case Method.E2: p = 2; break; case Method.H: p = 3; break; case Method.RK3: p = 3; break; case Method.RK4: p = 4; break; case Method.P38: p = 4; break; case Method.F: p = 3; break; default: p = 4; break; } double RR; if (A.RowCount != A.ColCount) { RR = ((uh2 - val2) / (1 - 1.0 / Math.Pow(2, p))).EuqlidNorm; } else { RR = ((uh2 - val1) / (1 - 1.0 / Math.Pow(2, p))).EuqlidNorm; } /*if (RR < eps / 64) { step *= 2; stepchange++; } * else */ if (RR > eps) { step /= 2; stepchange++; } else { begin += step; step = thisstep;//возврат к исходному шагу if (A.RowCount != A.ColCount) { res.Add(new PointV(begin, val2)); } else { res.Add(new PointV(begin, val1)); } } } else if (A.RowCount != A.ColCount && stepchange <= MaxStepChange) { if (R > eps) { step /= 2; stepchange++; } else if (R <= eps / 64) { begin += step; res.Add(new PointV(begin, val2)); step *= 2; stepchange++; } else { begin += step; res.Add(new PointV(begin, val2)); } } else { begin += step; res.Add(new PointV(begin, val1)); } if (Math.Abs(end - begin) < step) { step = Math.Abs(end - begin); } } return(res); }
/// <summary> /// Решение задачи о стрельбе /// </summary> /// <param name="f">Свободная функция в системе ОДУ</param> /// <param name="F">Функция из граничных условий</param> /// <param name="alp">Вектор альфа начального приближения при поиске корня</param> /// <param name="list">Промежуточный список вектор-функций</param> /// <param name="vlist">Промежуточный список векторов</param> /// <param name="netlist">Промежуточный список вектор-функций (так как делегаты передаются плохо)</param> /// <param name="begin">Начало отрезка задания аргумента</param> /// <param name="end">Конец отрезка задания аргумента</param> /// <param name="stepcount">Число шагов при решении ОДУ</param> /// <param name="M">Метод решения ОДУ</param> /// <param name="eps">Погрешность</param> /// <param name="l">Коэффициент для метода итераций</param> /// <param name="controlstep">Нужно ли следить за шагом при решении ОДУ</param> /// <returns></returns> public static VectorFunc ShootQu(VRealFunc f, TwoVectorToVector F, Vectors alp, out List <VectorFunc> list, out List <Vectors> vlist, out List <VectorNetFunc> netlist, double begin = 0, double end = 10, int stepcount = 50, Method M = Method.RK4, double eps = 1e-5, double l = 0.1, bool controlstep = false) { list = new List <VectorFunc>(); vlist = new List <Vectors>(); netlist = new List <VectorNetFunc>(); double step = (end - begin) / (stepcount - 1); VRealFunc u = (double t, Vectors v) => { var k = ODUsearch(f, v, begin, end, step, M, eps, controlstep); if (t == end) { return(k.Last().Item2); } double arg = begin; int i = 1; while (arg < t) { arg = k[i++].Item1; } return(k[--i].Item2); }; VectorToVector FF = (Vectors v) => F(v, u(end, v)); Vectors xn; if (FF(alp).EuqlidNorm > eps) { Vectors fx0 = FF(alp);//fx0.Show(); vlist.Add(fx0); list.Add((double t) => u(t, new Vectors(fx0))); VectorNetFunc tmp = new VectorNetFunc(); for (int i = 0; i < stepcount; i++) { double arg = begin + i * step; tmp.Add(new Tuple <double, Vectors>(arg, list.Last()(arg))); } netlist.Add(tmp); VectorToVector ef = (Vectors v) => v - l * FF(v); //double stnorm, stvector, neunorm, neuvector; bool delay = true; while ((ef(fx0) - fx0).EuqlidNorm > eps && delay) { xn = ef(fx0) - fx0; Console.WriteLine($"Norm f(v)-v ={xn.EuqlidNorm}"); //fx0.Show(); fx0 = ef(fx0); vlist.Add(fx0); //fx0.Show(); list.Add(new VectorFunc((double t) => u(t, fx0))); //$"list({3}) = {list.Last()(3)}".Show(); tmp = new VectorNetFunc(); for (int i = 0; i < stepcount; i++) { double arg = begin + i * step; tmp.Add(new Tuple <double, Vectors>(arg, list.Last()(arg))); } netlist.Add(tmp); if ((ef(fx0) - fx0 - xn).EuqlidNorm < eps / 1e4) { delay = false; } } } else { vlist.Add(alp); list.Add((double t) => u(t, new Vectors(alp))); VectorNetFunc tmp = new VectorNetFunc(); for (int i = 0; i < stepcount; i++) { double arg = begin + i * step; tmp.Add(new Tuple <double, Vectors>(arg, list.Last()(arg))); } netlist.Add(tmp); } return(list.Last()); }
private static void Get2Tmp(ref Vectors tmp, ref Vectors tmpp, double step, Matrix A, Vectors[] k, VRealFunc f, Vectors u, double t, int r) { tmp = new Vectors(tmp.Deg); tmpp = new Vectors(tmp.Deg); for (int i = 0; i < k.Length; i++) { Vectors tmp2 = new Vectors(tmp.Deg); for (int j = 0; j < i; j++) { tmp2 += A[i, j + 1] * k[j]; } k[i] = f(t + A[i, 0] * step, u + tmp2 * step); tmp += A[r, i + 1] * k[i]; if (A.RowCount != A.ColCount) { tmpp += A[r + 1, i + 1] * k[i]; } } }