10 #include <catch2/catch_test_macros.hpp> 
   11 #include <catch2/matchers/catch_matchers_floating_point.hpp> 
   15 using namespace nmodl;
 
   20 SCENARIO(
"Non-linear system to solve with Newton Solver", 
"[analytic][solver]") {
 
   21     GIVEN(
"1 linear eq") {
 
   23             void operator()(
const Eigen::Matrix<double, 1, 1>& X,
 
   24                             Eigen::Matrix<double, 1, 1>& ,
 
   25                             Eigen::Matrix<double, 1, 1>& F,
 
   26                             Eigen::Matrix<double, 1, 1>& J)
 const {
 
   28                 F[0] = -3.0 * X[0] + 3.0;
 
   33         Eigen::Matrix<double, 1, 1> X{22.2536};
 
   34         Eigen::Matrix<double, 1, 1> dX;
 
   35         Eigen::Matrix<double, 1, 1> F;
 
   36         Eigen::Matrix<double, 1, 1> J;
 
   40         THEN(
"find the solution") {
 
   43             REQUIRE(iter_newton == 1);
 
   44             REQUIRE_THAT(X[0], Catch::Matchers::WithinRel(1.0, 0.01));
 
   49     GIVEN(
"1 non-linear eq") {
 
   51             void operator()(
const Eigen::Matrix<double, 1, 1>& X,
 
   52                             Eigen::Matrix<double, 1, 1>& ,
 
   53                             Eigen::Matrix<double, 1, 1>& F,
 
   54                             Eigen::Matrix<double, 1, 1>& J)
 const {
 
   55                 F[0] = -3.0 * X[0] + std::sin(X[0]) + std::log(X[0] * X[0] + 11.435243) + 3.0;
 
   56                 J(0, 0) = -3.0 + std::cos(X[0]) + 2.0 * X[0] / (X[0] * X[0] + 11.435243);
 
   59         Eigen::Matrix<double, 1, 1> X{-0.21421};
 
   60         Eigen::Matrix<double, 1, 1> dX;
 
   61         Eigen::Matrix<double, 1, 1> F;
 
   62         Eigen::Matrix<double, 1, 1> J;
 
   66         THEN(
"find the solution") {
 
   69             REQUIRE(iter_newton > 0);
 
   70             REQUIRE_THAT(X[0], Catch::Matchers::WithinRel(2.19943987001206, 0.01));
 
   75     GIVEN(
"system of 2 non-linear eqs") {
 
   77             void operator()(
const Eigen::Matrix<double, 2, 1>& X,
 
   78                             Eigen::Matrix<double, 2, 1>& ,
 
   79                             Eigen::Matrix<double, 2, 1>& F,
 
   80                             Eigen::Matrix<double, 2, 2>& J)
 const {
 
   81                 F[0] = -3.0 * X[0] * X[1] + X[0] + 2.0 * X[1] - 1.0;
 
   82                 F[1] = 4.0 * X[0] - 0.29999999999999999 * std::pow(X[1], 2) + X[1] + 0.4;
 
   83                 J(0, 0) = -3.0 * X[1] + 1.0;
 
   84                 J(0, 1) = -3.0 * X[0] + 2.0;
 
   86                 J(1, 1) = -0.59999999999999998 * X[1] + 1.0;
 
   89         Eigen::Matrix<double, 2, 1> X{0.2, 0.4};
 
   90         Eigen::Matrix<double, 2, 1> dX;
 
   91         Eigen::Matrix<double, 2, 1> F;
 
   92         Eigen::Matrix<double, 2, 2> J;
 
   96         THEN(
"find a solution") {
 
   99             REQUIRE(iter_newton > 0);
 
  104     GIVEN(
"system of 3 non-linear eqs") {
 
  107             double _y_old = -231.5;
 
  108             double _z_old = 1.4565;
 
  115             void operator()(
const Eigen::Matrix<double, 3, 1>& X,
 
  116                             Eigen::Matrix<double, 3, 1>& ,
 
  117                             Eigen::Matrix<double, 3, 1>& F,
 
  118                             Eigen::Matrix<double, 3, 3>& J)
 const {
 
  119                 F(0) = -(-_x_old - dt * (a * std::pow(X[0], 2) + X[1]) + X[0]);
 
  120                 F(1) = -(_y_old - dt * (a * X[0] + b * X[1] + d) + X[1]);
 
  121                 F(2) = -(_z_old - dt * (e * z - 3.0 * X[0] + 2.0 * X[1]) + X[2]);
 
  122                 J(0, 0) = 2.0 * a * dt * X[0] - 1.0;
 
  126                 J(1, 1) = b * dt - 1.0;
 
  130                 J(2, 2) = dt * e - 1.0;
 
  133         Eigen::Matrix<double, 3, 1> X{0.21231, 0.4435, -0.11537};
 
  134         Eigen::Matrix<double, 3, 1> dX;
 
  135         Eigen::Matrix<double, 3, 1> F;
 
  136         Eigen::Matrix<double, 3, 3> J;
 
  140         THEN(
"find a solution") {
 
  141             CAPTURE(iter_newton);
 
  143             REQUIRE(iter_newton > 0);
 
  148     GIVEN(
"system of 4 non-linear eqs") {
 
  150             double X0_old = 1.2345;
 
  151             double X1_old = 1.2345;
 
  152             double X2_old = 1.2345;
 
  153             double X3_old = 1.2345;
 
  155             void operator()(
const Eigen::Matrix<double, 4, 1>& X,
 
  156                             Eigen::Matrix<double, 4, 1>& ,
 
  157                             Eigen::Matrix<double, 4, 1>& F,
 
  158                             Eigen::Matrix<double, 4, 4>& J)
 const {
 
  159                 F[0] = -(-3.0 * X[0] * X[2] * dt + X[0] - X0_old + 2.0 * dt / X[1]);
 
  160                 F[1] = -(X[1] - X1_old + dt * (4.0 * X[0] - 6.2 * X[1] + X[3]));
 
  161                 F[2] = -((X[2] * (X[2] - X2_old) - dt * (X[2] * (-1.2 * X[1] + 3.0) + 0.3)) / X[2]);
 
  162                 F[3] = -(-4.0 * X[0] * X[1] * X[2] * dt + X[3] - X3_old + 6.0 * dt / X[2]);
 
  163                 J(0, 0) = 3.0 * X[2] * dt - 1.0;
 
  164                 J(0, 1) = 2.0 * dt / std::pow(X[1], 2);
 
  165                 J(0, 2) = 3.0 * X[0] * dt;
 
  168                 J(1, 1) = 6.2 * dt - 1.0;
 
  173                 J(2, 2) = -1.0 - 0.3 * dt / std::pow(X[2], 2);
 
  175                 J(3, 0) = 4.0 * X[1] * X[2] * dt;
 
  176                 J(3, 1) = 4.0 * X[0] * X[2] * dt;
 
  177                 J(3, 2) = 4.0 * X[0] * X[1] * dt + 6.0 * dt / std::pow(X[2], 2);
 
  181         Eigen::Matrix<double, 4, 1> X{0.21231, 0.4435, -0.11537, -0.8124312};
 
  182         Eigen::Matrix<double, 4, 1> dX;
 
  183         Eigen::Matrix<double, 4, 1> F;
 
  184         Eigen::Matrix<double, 4, 4> J;
 
  188         THEN(
"find a solution") {
 
  189             CAPTURE(iter_newton);
 
  191             REQUIRE(iter_newton > 0);
 
  196     GIVEN(
"system of 5 non-linear eqs") {
 
  198             void operator()(
const Eigen::Matrix<double, 5, 1>& X,
 
  199                             Eigen::Matrix<double, 5, 1>& ,
 
  200                             Eigen::Matrix<double, 5, 1>& F,
 
  201                             Eigen::Matrix<double, 5, 5>& J)
 const {
 
  202                 F[0] = -3.0 * X[0] * X[2] + X[0] + 2.0 / X[1];
 
  203                 F[1] = 4.0 * X[0] - 5.2 * X[1] + X[3];
 
  204                 F[2] = 1.2 * X[1] + X[2] - 3.0 - 0.3 / X[2];
 
  205                 F[3] = -4.0 * X[0] * X[1] * X[2] + X[3] + 6.0 / X[2];
 
  206                 F[4] = (-4.0 * X[0] + (X[4] + cos(X[1])) * (X[1] * X[2] - X[3] * X[4])) /
 
  207                        (X[1] * X[2] - X[3] * X[4]);
 
  208                 J(0, 0) = -3.0 * X[2] + 1.0;
 
  209                 J(0, 1) = -2.0 / std::pow(X[1], 2);
 
  210                 J(0, 2) = -3.0 * X[0];
 
  220                 J(2, 2) = 1.0 + 0.3 / std::pow(X[2], 2);
 
  223                 J(3, 0) = -4.0 * X[1] * X[2];
 
  224                 J(3, 1) = -4.0 * X[0] * X[2];
 
  225                 J(3, 2) = -4.0 * X[0] * X[1] - 6.0 / std::pow(X[2], 2);
 
  228                 J(4, 0) = -4.0 / (X[1] * X[2] - X[3] * X[4]);
 
  229                 J(4, 1) = 4.0 * X[0] * X[2] / std::pow(X[1] * X[2] - X[3] * X[4], 2) -
 
  231                 J(4, 2) = 4.0 * X[0] * X[1] / std::pow(X[1] * X[2] - X[3] * X[4], 2);
 
  232                 J(4, 3) = -4.0 * X[0] * X[4] / std::pow(X[1] * X[2] - X[3] * X[4], 2);
 
  233                 J(4, 4) = -4.0 * X[0] * X[3] / std::pow(X[1] * X[2] - X[3] * X[4], 2) + 1.0;
 
  236         Eigen::Matrix<double, 5, 1> X;
 
  237         X << 8.234, -245.46, 123.123, 0.8343, 5.555;
 
  238         Eigen::Matrix<double, 5, 1> dX;
 
  239         Eigen::Matrix<double, 5, 1> F;
 
  240         Eigen::Matrix<double, 5, 5> J;
 
  242         int iter_newton = newton::newton_solver<5, functor>(X, fn);
 
  244         THEN(
"find a solution") {
 
  245             CAPTURE(iter_newton);
 
  247             REQUIRE(iter_newton > 0);
 
  252     GIVEN(
"system of 10 non-linear eqs") {
 
  254             void operator()(
const Eigen::Matrix<double, 10, 1>& X,
 
  255                             Eigen::Matrix<double, 10, 1>& ,
 
  256                             Eigen::Matrix<double, 10, 1>& F,
 
  257                             Eigen::Matrix<double, 10, 10>& J)
 const {
 
  258                 F[0] = -3.0 * X[0] * X[1] + X[0] + 2.0 * X[1];
 
  259                 F[1] = 4.0 * X[0] - 0.29999999999999999 * std::pow(X[1], 2) + X[1];
 
  260                 F[2] = 2.0 * X[1] + X[2] + 2.0 * X[3] * X[5] * X[7] - 3.0 * X[4] * X[8] - X[5];
 
  261                 F[3] = 4.0 * X[0] - 0.29999999999999999 * std::pow(X[1], 2) + X[3] -
 
  263                 F[4] = -3.0 * X[0] * X[7] + 2.0 * X[1] - 4.0 * X[3] * X[8] + X[4];
 
  264                 F[5] = -X[2] * X[5] * X[8] + 4.0 * X[3] - 0.29999999999999999 * X[4] * X[9] + X[5];
 
  265                 F[6] = -3.0 * X[0] * X[1] - 2.1000000000000001 * X[3] * X[4] * X[5] + X[6] +
 
  267                 F[7] = 4.0 * X[0] - 0.29999999999999999 * X[6] * X[7] + X[7];
 
  268                 F[8] = -3.0 * X[0] * X[1] - X[2] * X[3] * X[4] * std::pow(X[5], 2) + 2.0 * X[5] +
 
  270                 F[9] = -0.29999999999999999 * X[2] * X[4] + 4.0 * std::pow(X[9], 2) + X[9];
 
  271                 J(0, 0) = -3.0 * X[1] + 1.0;
 
  272                 J(0, 1) = -3.0 * X[0] + 2.0;
 
  282                 J(1, 1) = -0.59999999999999998 * X[1] + 1.0;
 
  294                 J(2, 3) = 2.0 * X[5] * X[7];
 
  295                 J(2, 4) = -3.0 * X[8];
 
  296                 J(2, 5) = 2.0 * X[3] * X[7] - 1.0;
 
  298                 J(2, 7) = 2.0 * X[3] * X[5];
 
  299                 J(2, 8) = -3.0 * X[4];
 
  302                 J(3, 1) = -0.59999999999999998 * X[1];
 
  305                 J(3, 4) = -X[6] * X[7];
 
  307                 J(3, 6) = -X[4] * X[7];
 
  308                 J(3, 7) = -X[4] * X[6];
 
  311                 J(4, 0) = -3.0 * X[7];
 
  314                 J(4, 3) = -4.0 * X[8];
 
  318                 J(4, 7) = -3.0 * X[0];
 
  319                 J(4, 8) = -4.0 * X[3];
 
  323                 J(5, 2) = -X[5] * X[8];
 
  325                 J(5, 4) = -0.29999999999999999 * X[9];
 
  326                 J(5, 5) = -X[2] * X[8] + 1.0;
 
  329                 J(5, 8) = -X[2] * X[5];
 
  330                 J(5, 9) = -0.29999999999999999 * X[4];
 
  331                 J(6, 0) = -3.0 * X[1];
 
  332                 J(6, 1) = -3.0 * X[0];
 
  334                 J(6, 3) = -2.1000000000000001 * X[4] * X[5];
 
  335                 J(6, 4) = -2.1000000000000001 * X[3] * X[5];
 
  336                 J(6, 5) = -2.1000000000000001 * X[3] * X[4];
 
  347                 J(7, 6) = -0.29999999999999999 * X[7];
 
  348                 J(7, 7) = -0.29999999999999999 * X[6] + 1.0;
 
  351                 J(8, 0) = -3.0 * X[1];
 
  352                 J(8, 1) = -3.0 * X[0];
 
  353                 J(8, 2) = -X[3] * X[4] * std::pow(X[5], 2);
 
  354                 J(8, 3) = -X[2] * X[4] * std::pow(X[5], 2);
 
  355                 J(8, 4) = -X[2] * X[3] * std::pow(X[5], 2);
 
  356                 J(8, 5) = -2.0 * X[2] * X[3] * X[4] * X[5] + 2.0;
 
  363                 J(9, 2) = -0.29999999999999999 * X[4];
 
  365                 J(9, 4) = -0.29999999999999999 * X[2];
 
  370                 J(9, 9) = 8.0 * X[9] + 1.0;
 
  374         Eigen::Matrix<double, 10, 1> X;
 
  375         X << 8.234, -5.46, 1.123, 0.8343, 5.555, 18.234, -2.46, 0.123, 10.8343, -4.685;
 
  376         Eigen::Matrix<double, 10, 1> dX;
 
  377         Eigen::Matrix<double, 10, 1> F;
 
  378         Eigen::Matrix<double, 10, 10> J;
 
  380         int iter_newton = newton::newton_solver<10, functor>(X, fn);
 
  382         THEN(
"find a solution") {
 
  383             CAPTURE(iter_newton);
 
  385             REQUIRE(iter_newton > 0);