trunk/src/emu/netlist/analog/nld_solver.c
| r30979 | r30980 | |
| 17 | 17 | #define VECTALT 1 |
| 18 | 18 | #define USE_GABS 0 |
| 19 | 19 | #define USE_MATRIX_GS 0 |
| 20 | //#define SORP 1.059 |
| 20 | 21 | #define SORP 1.059 |
| 22 | // savings are eaten up by effort |
| 23 | #define USE_LINEAR_PREDICTION (0) |
| 21 | 24 | |
| 22 | 25 | #define SOLVER_VERBOSE_OUT(x) do {} while (0) |
| 23 | 26 | //#define SOLVER_VERBOSE_OUT(x) printf x |
| r30979 | r30980 | |
| 103 | 106 | // ---------------------------------------------------------------------------------------- |
| 104 | 107 | |
| 105 | 108 | ATTR_COLD netlist_matrix_solver_t::netlist_matrix_solver_t() |
| 106 | | : m_calculations(0) |
| 109 | : m_calculations(0), m_cur_ts(0) |
| 107 | 110 | { |
| 108 | 111 | } |
| 109 | 112 | |
| r30979 | r30980 | |
| 202 | 205 | netlist_matrix_solver_direct_t<m_N, _storage_N>::netlist_matrix_solver_direct_t(int size) |
| 203 | 206 | : netlist_matrix_solver_t() |
| 204 | 207 | , m_dim(size) |
| 208 | , m_lp_fact(0) |
| 205 | 209 | { |
| 206 | 210 | m_terms = new terms_t *[N()]; |
| 207 | 211 | m_rails_temp = new terms_t[N()]; |
| r30979 | r30980 | |
| 230 | 234 | } |
| 231 | 235 | |
| 232 | 236 | template <int m_N, int _storage_N> |
| 233 | | ATTR_HOT double netlist_matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep(const double hn) |
| 237 | ATTR_HOT double netlist_matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep() |
| 234 | 238 | { |
| 235 | 239 | double new_solver_timestep = m_params.m_max_timestep; |
| 236 | 240 | |
| r30979 | r30980 | |
| 249 | 253 | { |
| 250 | 254 | netlist_analog_net_t *n = m_nets[k]; |
| 251 | 255 | #endif |
| 252 | | double DD_n = (n->m_cur_Analog - n->m_last_Analog); |
| 256 | const double DD_n = (n->m_cur_Analog - m_last_V[k]); |
| 257 | const double hn = current_timestep(); |
| 253 | 258 | |
| 254 | 259 | double DD2 = (DD_n / hn - n->m_DD_n_m_1 / n->m_h_n_m_1) / (hn + n->m_h_n_m_1); |
| 255 | 260 | double new_net_timestep; |
| r30979 | r30980 | |
| 276 | 281 | { |
| 277 | 282 | // avoid recursive calls. Inputs are updated outside this call |
| 278 | 283 | for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p)) |
| 279 | | if ((*p)->m_proxied_net->m_last_Analog != (*p)->m_proxied_net->m_cur_Analog) |
| 280 | | (*p)->set_Q((*p)->m_proxied_net->m_cur_Analog); |
| 284 | (*p)->set_Q((*p)->m_proxied_net->m_cur_Analog); |
| 281 | 285 | |
| 282 | 286 | for (int k = 0; k < m_nets.count(); k++) |
| 283 | 287 | { |
| r30979 | r30980 | |
| 337 | 341 | m_step_devices[k]->step_time(dd); |
| 338 | 342 | } |
| 339 | 343 | |
| 344 | template<class C > |
| 345 | void netlist_matrix_solver_t::solve_base(C *p) |
| 346 | { |
| 347 | if (is_dynamic()) |
| 348 | { |
| 349 | int this_resched; |
| 350 | int newton_loops = 0; |
| 351 | do |
| 352 | { |
| 353 | update_dynamic(); |
| 354 | // Gauss-Seidel will revert to Gaussian elemination if steps exceeded. |
| 355 | this_resched = p->vsolve_non_dynamic(); |
| 356 | newton_loops++; |
| 357 | } while (this_resched > 1 && newton_loops < m_params.m_nr_loops); |
| 358 | |
| 359 | // reschedule .... |
| 360 | if (this_resched > 1 && !m_Q_sync.net().is_queued()) |
| 361 | { |
| 362 | netlist().warning("NEWTON_LOOPS exceeded ... reschedule"); |
| 363 | m_Q_sync.net().reschedule_in_queue(m_params.m_nt_sync_delay); |
| 364 | } |
| 365 | } |
| 366 | else |
| 367 | { |
| 368 | p->vsolve_non_dynamic(); |
| 369 | } |
| 370 | } |
| 371 | |
| 340 | 372 | ATTR_HOT double netlist_matrix_solver_t::solve() |
| 341 | 373 | { |
| 342 | 374 | |
| r30979 | r30980 | |
| 347 | 379 | if (delta < netlist_time::from_nsec(1)) |
| 348 | 380 | return -1.0; |
| 349 | 381 | |
| 350 | | NL_VERBOSE_OUT(("Step!\n")); |
| 351 | 382 | /* update all terminals for new time step */ |
| 352 | 383 | m_last_step = now; |
| 384 | m_cur_ts = delta.as_double(); |
| 385 | |
| 353 | 386 | step(delta); |
| 354 | 387 | |
| 355 | | if (is_dynamic()) |
| 356 | | { |
| 357 | | int this_resched; |
| 358 | | int newton_loops = 0; |
| 359 | | do |
| 360 | | { |
| 361 | | update_dynamic(); |
| 362 | | // Gauss-Seidel will revert to Gaussian elemination if steps exceeded. |
| 363 | | this_resched = vsolve_non_dynamic(); |
| 364 | | newton_loops++; |
| 365 | | } while (this_resched > 1 && newton_loops < m_params.m_nr_loops); |
| 388 | const double next_time_step = vsolve(); |
| 366 | 389 | |
| 367 | | // reschedule .... |
| 368 | | if (this_resched > 1 && !m_Q_sync.net().is_queued()) |
| 369 | | { |
| 370 | | netlist().warning("NEWTON_LOOPS exceeded ... reschedule"); |
| 371 | | m_Q_sync.net().reschedule_in_queue(m_params.m_nt_sync_delay); |
| 372 | | return 1.0; |
| 373 | | } |
| 374 | | } |
| 375 | | else |
| 376 | | { |
| 377 | | vsolve_non_dynamic(); |
| 378 | | } |
| 379 | | const double next_time_step = compute_next_timestep(delta.as_double()); |
| 380 | 390 | update_inputs(); |
| 381 | 391 | return next_time_step; |
| 382 | 392 | } |
| r30979 | r30980 | |
| 384 | 394 | template <int m_N, int _storage_N> |
| 385 | 395 | void netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::log_stats() |
| 386 | 396 | { |
| 387 | | #if 0 |
| 397 | #if 1 |
| 388 | 398 | printf("==============================================\n"); |
| 389 | 399 | printf("Solver %s\n", this->name().cstr()); |
| 390 | 400 | printf(" ==> %d nets\n", this->N()); //, (*(*groups[i].first())->m_core_terms.first())->name().cstr()); |
| r30979 | r30980 | |
| 532 | 542 | akk = akk + gt[i]; |
| 533 | 543 | } |
| 534 | 544 | #else |
| 535 | | const netlist_terminal_t * const * terms = this->m_terms[k]->terms(); |
| 536 | 545 | m_terms[k]->ops()->sum2(Idr, gt, rhsk, akk); |
| 537 | 546 | #endif |
| 538 | 547 | double * const * RESTRICT other_cur_analog = m_terms[k]->other_curanalog(); |
| r30979 | r30980 | |
| 684 | 693 | { |
| 685 | 694 | for (int i = 0; i < this->N(); i++) |
| 686 | 695 | { |
| 687 | | this->m_nets[i]->m_cur_Analog = this->m_nets[i]->m_new_Analog = V[i]; |
| 696 | this->m_nets[i]->m_cur_Analog = V[i]; |
| 688 | 697 | } |
| 689 | 698 | if (store_RHS) |
| 690 | 699 | { |
| r30979 | r30980 | |
| 696 | 705 | } |
| 697 | 706 | |
| 698 | 707 | template <int m_N, int _storage_N> |
| 708 | ATTR_HOT double netlist_matrix_solver_direct_t<m_N, _storage_N>::vsolve() |
| 709 | { |
| 710 | solve_base<netlist_matrix_solver_direct_t>(this); |
| 711 | return this->compute_next_timestep(); |
| 712 | } |
| 713 | |
| 714 | |
| 715 | template <int m_N, int _storage_N> |
| 699 | 716 | ATTR_HOT int netlist_matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic() |
| 700 | 717 | { |
| 701 | 718 | double new_v[_storage_N] = { 0.0 }; |
| r30979 | r30980 | |
| 719 | 736 | } |
| 720 | 737 | |
| 721 | 738 | template <int m_N, int _storage_N> |
| 722 | | ATTR_HOT int netlist_matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic() |
| 739 | ATTR_HOT inline int netlist_matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic() |
| 723 | 740 | { |
| 724 | 741 | this->build_LE(); |
| 725 | 742 | |
| r30979 | r30980 | |
| 731 | 748 | // netlist_matrix_solver - Direct1 |
| 732 | 749 | // ---------------------------------------------------------------------------------------- |
| 733 | 750 | |
| 734 | | ATTR_HOT int netlist_matrix_solver_direct1_t::vsolve_non_dynamic() |
| 751 | ATTR_HOT double netlist_matrix_solver_direct1_t::vsolve() |
| 735 | 752 | { |
| 753 | solve_base<netlist_matrix_solver_direct1_t>(this); |
| 754 | return this->compute_next_timestep(); |
| 755 | } |
| 736 | 756 | |
| 757 | ATTR_HOT inline int netlist_matrix_solver_direct1_t::vsolve_non_dynamic() |
| 758 | { |
| 759 | |
| 737 | 760 | netlist_analog_net_t *net = m_nets[0]; |
| 738 | 761 | this->build_LE(); |
| 739 | 762 | //NL_VERBOSE_OUT(("%f %f\n", new_val, m_RHS[0] / m_A[0][0]); |
| r30979 | r30980 | |
| 743 | 766 | double e = (new_val - net->m_cur_Analog); |
| 744 | 767 | double cerr = fabs(e); |
| 745 | 768 | |
| 746 | | net->m_cur_Analog = net->m_new_Analog = new_val; |
| 769 | net->m_cur_Analog = new_val; |
| 747 | 770 | |
| 748 | 771 | if (is_dynamic() && (cerr > m_params.m_accuracy)) |
| 749 | 772 | { |
| r30979 | r30980 | |
| 760 | 783 | // netlist_matrix_solver - Direct2 |
| 761 | 784 | // ---------------------------------------------------------------------------------------- |
| 762 | 785 | |
| 763 | | ATTR_HOT int netlist_matrix_solver_direct2_t::vsolve_non_dynamic() |
| 786 | ATTR_HOT double netlist_matrix_solver_direct2_t::vsolve() |
| 764 | 787 | { |
| 788 | solve_base<netlist_matrix_solver_direct2_t>(this); |
| 789 | return this->compute_next_timestep(); |
| 790 | } |
| 765 | 791 | |
| 792 | ATTR_HOT inline int netlist_matrix_solver_direct2_t::vsolve_non_dynamic() |
| 793 | { |
| 794 | |
| 766 | 795 | build_LE(); |
| 767 | 796 | |
| 768 | 797 | const double a = m_A[0][0]; |
| r30979 | r30980 | |
| 776 | 805 | |
| 777 | 806 | if (is_dynamic()) |
| 778 | 807 | { |
| 779 | | double err = delta(new_val); |
| 808 | double err = this->delta(new_val); |
| 780 | 809 | store(new_val, true); |
| 781 | 810 | if (err > m_params.m_accuracy ) |
| 782 | 811 | return 2; |
| r30979 | r30980 | |
| 792 | 821 | // ---------------------------------------------------------------------------------------- |
| 793 | 822 | |
| 794 | 823 | template <int m_N, int _storage_N> |
| 795 | | ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::vsolve_non_dynamic() |
| 824 | ATTR_HOT double netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::vsolve() |
| 796 | 825 | { |
| 826 | /* |
| 827 | * enable linear prediction on first newton pass |
| 828 | */ |
| 829 | |
| 830 | if (USE_LINEAR_PREDICTION) |
| 831 | for (int k = 0; k < this->N(); k++) |
| 832 | { |
| 833 | this->m_last_V[k] = this->m_nets[k]->m_cur_Analog; |
| 834 | this->m_nets[k]->m_cur_Analog = this->m_nets[k]->m_cur_Analog + this->m_Vdelta[k] * this->current_timestep() * m_lp_fact; |
| 835 | } |
| 836 | else |
| 837 | for (int k = 0; k < this->N(); k++) |
| 838 | { |
| 839 | this->m_last_V[k] = this->m_nets[k]->m_cur_Analog; |
| 840 | } |
| 841 | |
| 842 | solve_base(this); |
| 843 | |
| 844 | if (USE_LINEAR_PREDICTION) |
| 845 | { |
| 846 | double sq = 0; |
| 847 | double sqo = 0; |
| 848 | for (int k = 0; k < this->N(); k++) |
| 849 | { |
| 850 | netlist_analog_net_t *n = this->m_nets[k]; |
| 851 | double nv = (n->m_cur_Analog - this->m_last_V[k]) / this->current_timestep(); |
| 852 | sq += nv * nv; |
| 853 | sqo += this->m_Vdelta[k] * this->m_Vdelta[k]; |
| 854 | this->m_Vdelta[k] = nv; |
| 855 | } |
| 856 | if (sqo > 1e-90) |
| 857 | m_lp_fact = sqrt(sq/sqo); |
| 858 | else |
| 859 | m_lp_fact = 0.0; |
| 860 | if (m_lp_fact > 2.0) |
| 861 | m_lp_fact = 2.0; |
| 862 | //printf("fact %f\n", fact); |
| 863 | } |
| 864 | |
| 865 | |
| 866 | return this->compute_next_timestep(); |
| 867 | } |
| 868 | |
| 869 | template <int m_N, int _storage_N> |
| 870 | ATTR_HOT inline int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::vsolve_non_dynamic() |
| 871 | { |
| 797 | 872 | /* The matrix based code looks a lot nicer but actually is 30% slower than |
| 798 | 873 | * the optimized code which works directly on the data structures. |
| 799 | 874 | * Need something like that for gaussian elimination as well. |
| 800 | 875 | */ |
| 801 | 876 | |
| 802 | 877 | #if USE_MATRIX_GS |
| 878 | static double ws = 1.0; |
| 803 | 879 | ATTR_ALIGN double new_v[_storage_N] = { 0.0 }; |
| 804 | 880 | const int iN = this->N(); |
| 805 | 881 | |
| r30979 | r30980 | |
| 809 | 885 | |
| 810 | 886 | this->build_LE(); |
| 811 | 887 | |
| 812 | | for (int k = 0; k < iN; k++) |
| 813 | 888 | { |
| 814 | | new_v[k] = this->m_nets[k]->m_cur_Analog; |
| 889 | double frob; |
| 890 | frob = 0; |
| 891 | for (int k = 0; k < iN; k++) |
| 892 | { |
| 893 | new_v[k] = this->m_nets[k]->m_cur_Analog; |
| 894 | for (int i = 0; i < iN; i++) |
| 895 | { |
| 896 | frob += this->m_A[k][i] * this->m_A[k][i]; |
| 897 | } |
| 898 | |
| 899 | } |
| 900 | double frobA = sqrt(frob /(iN)); |
| 901 | if (1 &&frobA < 1.0) |
| 902 | //ws = 2.0 / (1.0 + sqrt(1.0-frobA)); |
| 903 | ws = 2.0 / (2.0 - frobA); |
| 904 | else |
| 905 | ws = 1.0; |
| 906 | ws = 0.9; |
| 815 | 907 | } |
| 816 | 908 | |
| 817 | 909 | // Frobenius norm for (D-L)^(-1)U |
| 818 | | double frobU; |
| 819 | | double frobL; |
| 820 | | double frob; |
| 821 | | double norm; |
| 910 | //double frobU; |
| 911 | //double frobL; |
| 912 | //double norm; |
| 822 | 913 | do { |
| 823 | 914 | resched = false; |
| 824 | 915 | double cerr = 0.0; |
| 825 | | frobU = 0; |
| 826 | | frobL = 0; |
| 827 | | frob = 0; |
| 828 | | norm = 0; |
| 916 | //frobU = 0; |
| 917 | //frobL = 0; |
| 918 | //norm = 0; |
| 829 | 919 | |
| 830 | 920 | for (int k = 0; k < iN; k++) |
| 831 | 921 | { |
| 832 | 922 | double Idrive = 0; |
| 833 | | double norm_t = 0; |
| 923 | //double norm_t = 0; |
| 834 | 924 | // Reduction loops need -ffast-math |
| 835 | 925 | for (int i = 0; i < iN; i++) |
| 836 | 926 | Idrive += this->m_A[k][i] * new_v[i]; |
| 837 | 927 | |
| 838 | 928 | for (int i = 0; i < iN; i++) |
| 839 | 929 | { |
| 840 | | if (i < k) frobL += this->m_A[k][i] * this->m_A[k][i] / this->m_A[k][k] /this-> m_A[k][k]; |
| 841 | | if (i > k) frobU += this->m_A[k][i] * this->m_A[k][i] / this->m_A[k][k] / this->m_A[k][k]; |
| 842 | | frob += this->m_A[k][i] * this->m_A[k][i]; |
| 843 | | norm_t += fabs(this->m_A[k][i]); |
| 930 | //if (i < k) frobL += this->m_A[k][i] * this->m_A[k][i] / this->m_A[k][k] /this-> m_A[k][k]; |
| 931 | //if (i > k) frobU += this->m_A[k][i] * this->m_A[k][i] / this->m_A[k][k] / this->m_A[k][k]; |
| 932 | //norm_t += fabs(this->m_A[k][i]); |
| 844 | 933 | } |
| 845 | 934 | |
| 846 | | if (norm_t > norm) norm = norm_t; |
| 847 | | const double new_val = (this->m_RHS[k] - Idrive + this->m_A[k][k] * new_v[k]) / this->m_A[k][k]; |
| 935 | //if (norm_t > norm) norm = norm_t; |
| 936 | const double new_val = (1.0-ws) * new_v[k] + ws * (this->m_RHS[k] - Idrive + this->m_A[k][k] * new_v[k]) / this->m_A[k][k]; |
| 848 | 937 | |
| 849 | 938 | const double e = fabs(new_val - new_v[k]); |
| 850 | 939 | cerr = (e > cerr ? e : cerr); |
| r30979 | r30980 | |
| 856 | 945 | resched = true; |
| 857 | 946 | } |
| 858 | 947 | resched_cnt++; |
| 948 | //ATTR_UNUSED double frobUL = sqrt((frobU + frobL) / (double) (iN) / (double) (iN)); |
| 859 | 949 | } while (resched && (resched_cnt < this->m_params.m_gs_loops)); |
| 860 | | printf("Frobenius %f %f %f %f %f\n", sqrt(frobU), sqrt(frobL), sqrt(frobU * frobL + (double) iN), sqrt(frob), norm); |
| 861 | | frobU = sqrt(frobU); |
| 862 | | frobL = sqrt(frobL); |
| 863 | | printf("Estimate Frobenius %f\n", 1.0 - (1.0 - frobU -frobL) / (1.0 - frobL) ); // printf("Frobenius %f\n", sqrt(frob / (double) (iN * iN) )); |
| 950 | //printf("Frobenius %f %f %f %f %f\n", sqrt(frobU), sqrt(frobL), frobUL, frobA, norm); |
| 951 | //printf("Omega Estimate1 %f %f\n", 2.0 / (1.0 + sqrt(1-frobUL)), 2.0 / (1.0 + sqrt(1-frobA)) ); // printf("Frobenius %f\n", sqrt(frob / (double) (iN * iN) )); |
| 952 | //printf("Omega Estimate2 %f %f\n", 2.0 / (2.0 - frobUL), 2.0 / (2.0 - frobA) ); // printf("Frobenius %f\n", sqrt(frob / (double) (iN * iN) )); |
| 864 | 953 | |
| 865 | 954 | |
| 866 | 955 | this->store(new_v, false); |
| r30979 | r30980 | |
| 884 | 973 | const int iN = this->N(); |
| 885 | 974 | bool resched = false; |
| 886 | 975 | int resched_cnt = 0; |
| 887 | | /* some minor SOR helps on typical netlist matrices */ |
| 888 | 976 | |
| 889 | 977 | /* ideally, we could get an estimate for the spectral radius of |
| 890 | 978 | * Inv(D - L) * U |
| r30979 | r30980 | |
| 903 | 991 | |
| 904 | 992 | for (int k = 0; k < iN; k++) |
| 905 | 993 | { |
| 906 | | new_V[k] = this->m_nets[k]->m_new_Analog = this->m_nets[k]->m_cur_Analog; |
| 994 | new_V[k] = this->m_nets[k]->m_cur_Analog; |
| 907 | 995 | } |
| 908 | | |
| 909 | 996 | for (int k = 0; k < iN; k++) |
| 910 | 997 | { |
| 911 | 998 | double gtot_t = 0.0; |
| r30979 | r30980 | |
| 958 | 1045 | |
| 959 | 1046 | do { |
| 960 | 1047 | resched = false; |
| 961 | | double cerr = 0.0; |
| 1048 | //double cerr = 0.0; |
| 962 | 1049 | |
| 963 | 1050 | for (int k = 0; k < iN; k++) |
| 964 | 1051 | { |
| 965 | 1052 | const int * RESTRICT net_other = this->m_terms[k]->net_other(); |
| 966 | 1053 | const int railstart = this->m_terms[k]->m_railstart; |
| 967 | 1054 | const double * RESTRICT go = this->m_terms[k]->go(); |
| 968 | | // -msse2 -msse3 -msse4.1 -msse4.2 -mfpmath=sse -ftree-vectorizer-verbose=3 -fprefetch-loop-arrays -ffast-math |
| 969 | 1055 | |
| 970 | | double Idrive; |
| 971 | | |
| 972 | | Idrive = 0.0; |
| 1056 | double Idrive = 0.0; |
| 973 | 1057 | for (int i = 0; i < railstart; i++) |
| 974 | 1058 | Idrive = Idrive + go[i] * new_V[net_other[i]]; |
| 975 | 1059 | |
| 976 | 1060 | //double new_val = (net->m_cur_Analog * gabs[k] + iIdr) / (gtot[k]); |
| 977 | 1061 | const double new_val = new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k]; |
| 978 | 1062 | |
| 979 | | const double e = fabs(new_val - new_V[k]); |
| 980 | | cerr = (e > cerr ? e : cerr); |
| 1063 | resched = resched || (fabs(new_val - new_V[k]) > this->m_params.m_accuracy); |
| 1064 | new_V[k] = new_val; |
| 1065 | } |
| 981 | 1066 | |
| 982 | | new_V[k] = new_val; |
| 983 | | } |
| 984 | | if (cerr > this->m_params.m_accuracy) |
| 985 | | { |
| 986 | | resched = true; |
| 987 | | } |
| 988 | 1067 | resched_cnt++; |
| 989 | 1068 | } while (resched && (resched_cnt < this->m_params.m_gs_loops)); |
| 990 | 1069 | |
| 991 | 1070 | for (int k = 0; k < iN; k++) |
| 992 | | this->m_nets[k]->m_new_Analog = this->m_nets[k]->m_cur_Analog = new_V[k]; |
| 1071 | this->m_nets[k]->m_cur_Analog = new_V[k]; |
| 993 | 1072 | |
| 994 | 1073 | this->m_gs_total += resched_cnt; |
| 995 | 1074 | |
| r30979 | r30980 | |
| 1024 | 1103 | register_param("FREQ", m_freq, 48000.0); |
| 1025 | 1104 | |
| 1026 | 1105 | register_param("ACCURACY", m_accuracy, 1e-7); |
| 1027 | | register_param("GS_LOOPS", m_gs_loops, 9); // Gauss-Seidel loops |
| 1028 | | //register_param("GS_THRESHOLD", m_gs_threshold, 99); // below this value, gaussian elimination is used |
| 1106 | register_param("GS_LOOPS", m_gs_loops, 9); // Gauss-Seidel loops |
| 1029 | 1107 | register_param("GS_THRESHOLD", m_gs_threshold, 5); // below this value, gaussian elimination is used |
| 1030 | 1108 | register_param("NR_LOOPS", m_nr_loops, 25); // Newton-Raphson loops |
| 1031 | 1109 | register_param("PARALLEL", m_parallel, 0); |
| r30979 | r30980 | |
| 1180 | 1258 | |
| 1181 | 1259 | switch (net_count) |
| 1182 | 1260 | { |
| 1183 | | #if 1 |
| 1184 | 1261 | case 1: |
| 1185 | 1262 | ms = create_solver<1,1>(1, gs_threshold, use_specific); |
| 1186 | 1263 | break; |
| r30979 | r30980 | |
| 1208 | 1285 | case 12: |
| 1209 | 1286 | ms = create_solver<12,12>(12, gs_threshold, use_specific); |
| 1210 | 1287 | break; |
| 1211 | | #endif |
| 1212 | 1288 | default: |
| 1213 | 1289 | if (net_count <= 16) |
| 1214 | 1290 | { |
trunk/src/emu/netlist/analog/nld_solver.h
| r30979 | r30980 | |
| 196 | 196 | |
| 197 | 197 | ATTR_COLD virtual void vsetup(netlist_analog_net_t::list_t &nets) = 0; |
| 198 | 198 | |
| 199 | template<class C> |
| 200 | void solve_base(C *p); |
| 201 | |
| 199 | 202 | ATTR_HOT double solve(); |
| 200 | 203 | |
| 201 | 204 | ATTR_HOT inline bool is_dynamic() { return m_dynamic_devices.count() > 0; } |
| r30979 | r30980 | |
| 216 | 219 | protected: |
| 217 | 220 | |
| 218 | 221 | ATTR_COLD void setup(netlist_analog_net_t::list_t &nets); |
| 222 | ATTR_HOT void update_dynamic(); |
| 219 | 223 | |
| 220 | | // return true if a reschedule is needed ... |
| 221 | | ATTR_HOT virtual int vsolve_non_dynamic() = 0; |
| 224 | // should return next time step |
| 225 | ATTR_HOT virtual double vsolve() = 0; |
| 222 | 226 | |
| 223 | 227 | ATTR_COLD virtual void add_term(int net_idx, netlist_terminal_t *term) = 0; |
| 224 | 228 | |
| r30979 | r30980 | |
| 227 | 231 | |
| 228 | 232 | int m_calculations; |
| 229 | 233 | |
| 234 | ATTR_HOT inline const double current_timestep() { return m_cur_ts; } |
| 230 | 235 | private: |
| 231 | 236 | |
| 232 | 237 | netlist_time m_last_step; |
| 238 | double m_cur_ts; |
| 233 | 239 | dev_list_t m_step_devices; |
| 234 | 240 | dev_list_t m_dynamic_devices; |
| 235 | 241 | |
| r30979 | r30980 | |
| 238 | 244 | |
| 239 | 245 | ATTR_HOT void step(const netlist_time delta); |
| 240 | 246 | |
| 241 | | /* bring the whole system to the current time |
| 242 | | * Don't schedule a new calculation time. The recalculation has to be |
| 243 | | * triggered by the caller after the netlist element was changed. |
| 244 | | */ |
| 245 | | ATTR_HOT virtual double compute_next_timestep(const double) = 0; |
| 246 | | |
| 247 | 247 | ATTR_HOT void update_inputs(); |
| 248 | | ATTR_HOT void update_dynamic(); |
| 249 | 248 | |
| 250 | 249 | }; |
| 251 | 250 | |
| r30979 | r30980 | |
| 263 | 262 | |
| 264 | 263 | ATTR_HOT inline const int N() const { if (m_N == 0) return m_dim; else return m_N; } |
| 265 | 264 | |
| 265 | ATTR_HOT inline int vsolve_non_dynamic(); |
| 266 | |
| 266 | 267 | protected: |
| 267 | 268 | ATTR_COLD virtual void add_term(int net_idx, netlist_terminal_t *term); |
| 268 | 269 | |
| 269 | | ATTR_HOT virtual int vsolve_non_dynamic(); |
| 270 | ATTR_HOT virtual double vsolve(); |
| 271 | |
| 270 | 272 | ATTR_HOT int solve_non_dynamic(); |
| 271 | 273 | ATTR_HOT void build_LE(); |
| 272 | 274 | ATTR_HOT void gauss_LE(double (* RESTRICT x)); |
| 273 | 275 | ATTR_HOT double delta(const double (* RESTRICT V)); |
| 274 | 276 | ATTR_HOT void store(const double (* RESTRICT V), const bool store_RHS); |
| 275 | 277 | |
| 276 | | ATTR_HOT virtual double compute_next_timestep(const double); |
| 278 | /* bring the whole system to the current time |
| 279 | * Don't schedule a new calculation time. The recalculation has to be |
| 280 | * triggered by the caller after the netlist element was changed. |
| 281 | */ |
| 282 | ATTR_HOT double compute_next_timestep(); |
| 277 | 283 | |
| 278 | 284 | double m_A[_storage_N][((_storage_N + 7) / 8) * 8]; |
| 279 | 285 | double m_RHS[_storage_N]; |
| 280 | 286 | double m_last_RHS[_storage_N]; // right hand side - contains currents |
| 287 | double m_Vdelta[_storage_N]; |
| 288 | double m_last_V[_storage_N]; |
| 281 | 289 | |
| 282 | 290 | terms_t **m_terms; |
| 283 | 291 | |
| r30979 | r30980 | |
| 287 | 295 | vector_ops_t *m_row_ops[_storage_N + 1]; |
| 288 | 296 | |
| 289 | 297 | int m_dim; |
| 298 | double m_lp_fact; |
| 290 | 299 | }; |
| 291 | 300 | |
| 292 | 301 | template <int m_N, int _storage_N> |
| r30979 | r30980 | |
| 296 | 305 | |
| 297 | 306 | netlist_matrix_solver_gauss_seidel_t(int size) |
| 298 | 307 | : netlist_matrix_solver_direct_t<m_N, _storage_N>(size) |
| 308 | , m_lp_fact(0) |
| 299 | 309 | , m_gs_fail(0) |
| 300 | 310 | , m_gs_total(0) |
| 301 | 311 | {} |
| r30979 | r30980 | |
| 304 | 314 | |
| 305 | 315 | ATTR_COLD virtual void log_stats(); |
| 306 | 316 | |
| 317 | ATTR_HOT inline int vsolve_non_dynamic(); |
| 307 | 318 | protected: |
| 308 | | ATTR_HOT int vsolve_non_dynamic(); |
| 319 | ATTR_HOT virtual double vsolve(); |
| 309 | 320 | |
| 310 | 321 | private: |
| 322 | double m_lp_fact; |
| 311 | 323 | int m_gs_fail; |
| 312 | 324 | int m_gs_total; |
| 313 | 325 | |
| r30979 | r30980 | |
| 320 | 332 | netlist_matrix_solver_direct1_t() |
| 321 | 333 | : netlist_matrix_solver_direct_t<1, 1>(1) |
| 322 | 334 | {} |
| 335 | ATTR_HOT inline int vsolve_non_dynamic(); |
| 323 | 336 | protected: |
| 324 | | ATTR_HOT int vsolve_non_dynamic(); |
| 337 | ATTR_HOT virtual double vsolve(); |
| 325 | 338 | private: |
| 326 | 339 | }; |
| 327 | 340 | |
| r30979 | r30980 | |
| 332 | 345 | netlist_matrix_solver_direct2_t() |
| 333 | 346 | : netlist_matrix_solver_direct_t<2, 2>(2) |
| 334 | 347 | {} |
| 348 | ATTR_HOT inline int vsolve_non_dynamic(); |
| 335 | 349 | protected: |
| 336 | | ATTR_HOT int vsolve_non_dynamic(); |
| 350 | ATTR_HOT virtual double vsolve(); |
| 337 | 351 | private: |
| 338 | 352 | }; |
| 339 | 353 | |