diff options
author | 2019-03-25 22:44:58 +0100 | |
---|---|---|
committer | 2019-03-25 22:44:58 +0100 | |
commit | c24473ddff715ecec2e258a6eb38960cf8c8e98e (patch) | |
tree | 8ea44b6396a6129913c0aac13859b5de9965e972 /src/lib/netlist/solver/nld_solver.cpp | |
parent | 009cba4fb8102102168ef32870892438327f3705 (diff) | |
parent | 598cd5227223c3b04ca31f0dbc1981256d9ea3ff (diff) |
conflict resolution (nw)
Diffstat (limited to 'src/lib/netlist/solver/nld_solver.cpp')
-rw-r--r-- | src/lib/netlist/solver/nld_solver.cpp | 641 |
1 files changed, 323 insertions, 318 deletions
diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp index cae76caab1a..4734cc3624d 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -31,393 +31,398 @@ #pragma GCC optimize "ivopts" #endif -#include <algorithm> -#include <cmath> // <<= needed by windows build - -#include "../nl_lists.h" - -#include "../plib/pomp.h" - -#include "../nl_factory.h" - -#include "nld_solver.h" +#include "netlist/nl_lists.h" +#include "netlist/nl_factory.h" #include "nld_matrix_solver.h" - -#if 1 #include "nld_ms_direct.h" -#include "nld_ms_gcr.h" -#else -#include "nld_ms_direct_lu.h" -#endif -#include "nld_ms_w.h" -#include "nld_ms_sm.h" #include "nld_ms_direct1.h" #include "nld_ms_direct2.h" +#include "nld_ms_gcr.h" +#include "nld_ms_gmres.h" +#include "nld_ms_sm.h" #include "nld_ms_sor.h" #include "nld_ms_sor_mat.h" -#include "nld_ms_gmres.h" +#include "nld_ms_w.h" +#include "nld_solver.h" +#include "plib/pomp.h" + +#include <algorithm> +#include <cmath> namespace netlist { - namespace devices - { - - +namespace devices +{ -// ---------------------------------------------------------------------------------------- -// solver -// ---------------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------------- + // solver + // ---------------------------------------------------------------------------------------- -NETLIB_RESET(solver) -{ - for (std::size_t i = 0; i < m_mat_solvers.size(); i++) - m_mat_solvers[i]->do_reset(); -} + NETLIB_RESET(solver) + { + for (auto &s : m_mat_solvers) + s->reset(); + } -void NETLIB_NAME(solver)::stop() -{ - for (std::size_t i = 0; i < m_mat_solvers.size(); i++) - m_mat_solvers[i]->log_stats(); -} + void NETLIB_NAME(solver)::stop() + { + for (auto &s : m_mat_solvers) + s->log_stats(); + } -NETLIB_NAME(solver)::~NETLIB_NAME(solver)() -{ -} + NETLIB_UPDATE(solver) + { + if (m_params.m_dynamic_ts) + return; -NETLIB_UPDATE(solver) -{ - if (m_params.m_dynamic_ts) - return; + netlist_time now(exec().time()); + /* force solving during start up if there are no time-step devices */ + /* FIXME: Needs a more elegant solution */ + bool force_solve = (now < netlist_time::from_double(2 * m_params.m_max_timestep)); - /* force solving during start up if there are no time-step devices */ - /* FIXME: Needs a more elegant solution */ - bool force_solve = (netlist().time() < netlist_time::from_double(2 * m_params.m_max_timestep)); + std::size_t nthreads = std::min(static_cast<std::size_t>(m_parallel()), plib::omp::get_max_threads()); - std::size_t nthreads = std::min(m_parallel(), plib::omp::get_max_threads()); - std::size_t t_cnt = 0; - int solv[128]; - for (int i = 0; i < m_mat_solvers.size(); i++) - if (m_mat_solvers[i]->has_timestep_devices() || force_solve) - solv[t_cnt++] = i; + std::vector<matrix_solver_t *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_timestepping); - if (nthreads > 1 && t_cnt > 1) - { - plib::omp::set_num_threads(nthreads); - plib::omp::for_static(0, t_cnt, [this, &solv](int i) { ATTR_UNUSED const netlist_time ts = this->m_mat_solvers[solv[i]]->solve(); }); - } - else - for (auto & solver : m_mat_solvers) - if (solver->has_timestep_devices() || force_solve) - ATTR_UNUSED const netlist_time ts = solver->solve(); + if (nthreads > 1 && solvers.size() > 1) + { + plib::omp::set_num_threads(nthreads); + plib::omp::for_static(static_cast<std::size_t>(0), solvers.size(), [&solvers, now](std::size_t i) + { + const netlist_time ts = solvers[i]->solve(now); + plib::unused_var(ts); + }); + } + else + for (auto & solver : solvers) + { + const netlist_time ts = solver->solve(now); + plib::unused_var(ts); + } - for (auto & solver : m_mat_solvers) - if (solver->has_timestep_devices() || force_solve) + for (auto & solver : solvers) solver->update_inputs(); - /* step circuit */ - if (!m_Q_step.net().is_queued()) - { - m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_max_timestep)); + /* step circuit */ + if (!m_Q_step.net().is_queued()) + { + m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_max_timestep)); + } } -} - -template <class C> -std::unique_ptr<matrix_solver_t> create_it(netlist_t &nl, pstring name, solver_parameters_t ¶ms, std::size_t size) -{ - typedef C solver; - return plib::make_unique<solver>(nl, name, ¶ms, size); -} -template <std::size_t m_N, std::size_t storage_N> -std::unique_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername) -{ - if (pstring("SOR_MAT").equals(m_method())) + template <class C> + pool_owned_ptr<matrix_solver_t> create_it(netlist_state_t &nl, pstring name, solver_parameters_t ¶ms, std::size_t size) { - return create_it<matrix_solver_SOR_mat_t<m_N, storage_N>>(netlist(), solvername, m_params, size); - //typedef matrix_solver_SOR_mat_t<m_N,storage_N> solver_sor_mat; - //return plib::make_unique<solver_sor_mat>(netlist(), solvername, &m_params, size); + return pool().make_poolptr<C>(nl, name, ¶ms, size); } - else if (pstring("MAT_CR").equals(m_method())) + + template <typename FT, int SIZE> + pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername) { - if (size > 0) // GCR always outperforms MAT solver + if (m_method() == "SOR_MAT") + { + return create_it<matrix_solver_SOR_mat_t<FT, SIZE>>(state(), solvername, m_params, size); + //typedef matrix_solver_SOR_mat_t<m_N,storage_N> solver_sor_mat; + //return plib::make_unique<solver_sor_mat>(state(), solvername, &m_params, size); + } + else if (m_method() == "MAT_CR") + { + if (size > 0) // GCR always outperforms MAT solver + { + return create_it<matrix_solver_GCR_t<FT, SIZE>>(state(), solvername, m_params, size); + } + else + { + return create_it<matrix_solver_direct_t<FT, SIZE>>(state(), solvername, m_params, size); + } + } + else if (m_method() == "MAT") + { + return create_it<matrix_solver_direct_t<FT, SIZE>>(state(), solvername, m_params, size); + } + else if (m_method() == "SM") + { + /* Sherman-Morrison Formula */ + return create_it<matrix_solver_sm_t<FT, SIZE>>(state(), solvername, m_params, size); + } + else if (m_method() == "W") { - typedef matrix_solver_GCR_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); + /* Woodbury Formula */ + return create_it<matrix_solver_w_t<FT, SIZE>>(state(), solvername, m_params, size); + } + else if (m_method() == "SOR") + { + return create_it<matrix_solver_SOR_t<FT, SIZE>>(state(), solvername, m_params, size); + } + else if (m_method() == "GMRES") + { + return create_it<matrix_solver_GMRES_t<FT, SIZE>>(state(), solvername, m_params, size); } else { - typedef matrix_solver_direct_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); + log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method()); + return pool_owned_ptr<matrix_solver_t>(); } } - else if (pstring("MAT").equals(m_method())) - { - typedef matrix_solver_direct_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); - } - else if (pstring("SM").equals(m_method())) - { - /* Sherman-Morrison Formula */ - typedef matrix_solver_sm_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); - } - else if (pstring("W").equals(m_method())) - { - /* Woodbury Formula */ - typedef matrix_solver_w_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); - } - else if (pstring("SOR").equals(m_method())) - { - typedef matrix_solver_SOR_t<m_N,storage_N> solver_GS; - return plib::make_unique<solver_GS>(netlist(), solvername, &m_params, size); - } - else if (pstring("GMRES").equals(m_method())) - { - typedef matrix_solver_GMRES_t<m_N,storage_N> solver_GMRES; - return plib::make_unique<solver_GMRES>(netlist(), solvername, &m_params, size); - } - else + + template <typename FT, int SIZE> + pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver_x(std::size_t size, const pstring &solvername) { - log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method()); - return nullptr; + if (SIZE > 0) + { + if (size == SIZE) + return create_solver<FT, SIZE>(size, solvername); + else + return this->create_solver_x<FT, SIZE-1>(size, solvername); + } + else + { + if (size * 2 > -SIZE ) + return create_solver<FT, SIZE>(size, solvername); + else + return this->create_solver_x<FT, SIZE / 2>(size, solvername); + } } -} - -struct net_splitter -{ - bool already_processed(analog_net_t *n) + struct net_splitter { - if (n->isRailNet()) - return true; - for (auto & grp : groups) - if (plib::container::contains(grp, n)) + + bool already_processed(const analog_net_t &n) const + { + /* no need to process rail nets - these are known variables */ + if (n.isRailNet()) return true; - return false; - } + /* if it's already processed - no need to continue */ + for (auto & grp : groups) + if (plib::container::contains(grp, &n)) + return true; + return false; + } - void process_net(analog_net_t *n) - { - if (n->num_cons() == 0) - return; - /* add the net */ - groups.back().push_back(n); - for (auto &p : n->m_core_terms) + void process_net(analog_net_t &n) { - if (p->is_type(detail::terminal_type::TERMINAL)) + /* ignore empty nets. FIXME: print a warning message */ + if (n.num_cons() == 0) + return; + /* add the net */ + groups.back().push_back(&n); + /* process all terminals connected to this net */ + for (auto &term : n.core_terms()) { - terminal_t *pt = static_cast<terminal_t *>(p); - analog_net_t *other_net = &pt->m_otherterm->net(); - if (!already_processed(other_net)) - process_net(other_net); + /* only process analog terminals */ + if (term->is_type(detail::terminal_type::TERMINAL)) + { + auto *pt = static_cast<terminal_t *>(term); + /* check the connected terminal */ + analog_net_t &connected_net = pt->connected_terminal()->net(); + if (!already_processed(connected_net)) + process_net(connected_net); + } } } - } - void run(netlist_t &netlist) - { - for (auto & net : netlist.m_nets) + void run(netlist_state_t &netlist) { - netlist.log().debug("processing {1}\n", net->name()); - if (!net->isRailNet() && net->num_cons() > 0) + for (auto & net : netlist.nets()) { - netlist.log().debug(" ==> not a rail net\n"); - /* Must be an analog net */ - analog_net_t *n = static_cast<analog_net_t *>(net.get()); - if (!already_processed(n)) + netlist.log().debug("processing {1}\n", net->name()); + if (!net->isRailNet() && net->num_cons() > 0) { - groups.push_back(analog_net_t::list_t()); - process_net(n); + netlist.log().debug(" ==> not a rail net\n"); + /* Must be an analog net */ + auto &n = *static_cast<analog_net_t *>(net.get()); + if (!already_processed(n)) + { + groups.emplace_back(analog_net_t::list_t()); + process_net(n); + } } } } - } - std::vector<analog_net_t::list_t> groups; -}; + std::vector<analog_net_t::list_t> groups; + }; -void NETLIB_NAME(solver)::post_start() -{ - const bool use_specific = true; - - m_params.m_pivot = m_pivot(); - m_params.m_accuracy = m_accuracy(); - /* FIXME: Throw when negative */ - m_params.m_gs_loops = static_cast<unsigned>(m_gs_loops()); - m_params.m_nr_loops = static_cast<unsigned>(m_nr_loops()); - m_params.m_nr_recalc_delay = netlist_time::from_double(m_nr_recalc_delay()); - m_params.m_dynamic_lte = m_dynamic_lte(); - m_params.m_gs_sor = m_gs_sor(); - - m_params.m_min_timestep = m_dynamic_min_ts(); - m_params.m_dynamic_ts = (m_dynamic_ts() == 1 ? true : false); - m_params.m_max_timestep = netlist_time::from_double(1.0 / m_freq()).as_double(); - - if (m_params.m_dynamic_ts) + void NETLIB_NAME(solver)::post_start() { - m_params.m_max_timestep *= 1;//NL_FCONST(1000.0); - } - else - { - m_params.m_min_timestep = m_params.m_max_timestep; - } + m_params.m_pivot = m_pivot(); + m_params.m_accuracy = m_accuracy(); + /* FIXME: Throw when negative */ + m_params.m_gs_loops = static_cast<unsigned>(m_gs_loops()); + m_params.m_nr_loops = static_cast<unsigned>(m_nr_loops()); + m_params.m_nr_recalc_delay = netlist_time::from_double(m_nr_recalc_delay()); + m_params.m_dynamic_lte = m_dynamic_lte(); + m_params.m_gs_sor = m_gs_sor(); + + m_params.m_min_timestep = m_dynamic_min_ts(); + m_params.m_dynamic_ts = (m_dynamic_ts() == 1 ? true : false); + m_params.m_max_timestep = netlist_time::from_double(1.0 / m_freq()).as_double(); - //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::) + m_params.m_use_gabs = m_use_gabs(); + m_params.m_use_linear_prediction = m_use_linear_prediction(); + + + if (m_params.m_dynamic_ts) + { + m_params.m_max_timestep *= 1;//NL_FCONST(1000.0); + } + else + { + m_params.m_min_timestep = m_params.m_max_timestep; + } - // Override log statistics - pstring p = plib::util::environment("NL_STATS", ""); - if (p != "") - m_params.m_log_stats = p.as_long(); - else - m_params.m_log_stats = m_log_stats(); + //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::) - log().verbose("Scanning net groups ..."); - // determine net groups + // Override log statistics + pstring p = plib::util::environment("NL_STATS", ""); + if (p != "") + m_params.m_log_stats = plib::pstonum<decltype(m_params.m_log_stats)>(p); + else + m_params.m_log_stats = m_log_stats(); - net_splitter splitter; + log().verbose("Scanning net groups ..."); + // determine net groups - splitter.run(netlist()); + net_splitter splitter; - // setup the solvers - log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), netlist().m_nets.size()); - for (auto & grp : splitter.groups) - { - std::unique_ptr<matrix_solver_t> ms; - std::size_t net_count = grp.size(); - pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size()); + splitter.run(state()); - switch (net_count) + // setup the solvers + log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size()); + for (auto & grp : splitter.groups) { -#if 1 - case 1: - if (use_specific) - ms = plib::make_unique<matrix_solver_direct1_t>(netlist(), sname, &m_params); - else - ms = create_solver<1,1>(1, sname); - break; - case 2: - if (use_specific) - ms = plib::make_unique<matrix_solver_direct2_t>(netlist(), sname, &m_params); - else - ms = create_solver<2,2>(2, sname); - break; -#if 0 - case 3: - ms = create_solver<3,3>(3, sname); - break; - case 4: - ms = create_solver<4,4>(4, sname); - break; - case 5: - ms = create_solver<5,5>(5, sname); - break; - case 6: - ms = create_solver<6,6>(6, sname); - break; - case 7: - ms = create_solver<7,7>(7, sname); - break; - case 8: - ms = create_solver<8,8>(8, sname); - break; - case 9: - ms = create_solver<9,9>(9, sname); - break; - case 10: - ms = create_solver<10,10>(10, sname); - break; - case 11: - ms = create_solver<11,11>(11, sname); - break; - case 12: - ms = create_solver<12,12>(12, sname); - break; - case 15: - ms = create_solver<15,15>(15, sname); - break; - case 31: - ms = create_solver<31,31>(31, sname); - break; - case 35: - ms = create_solver<35,35>(35, sname); - break; - case 43: - ms = create_solver<43,43>(43, sname); - break; - case 49: - ms = create_solver<49,49>(49, sname); - break; -#endif -#if 0 - case 87: - ms = create_solver<87,87>(87, sname); - break; -#endif -#endif - default: - log().warning(MW_1_NO_SPECIFIC_SOLVER, net_count); - if (net_count <= 8) - { - ms = create_solver<0, 8>(net_count, sname); - } - else if (net_count <= 16) - { - ms = create_solver<0,16>(net_count, sname); - } - else if (net_count <= 32) - { - ms = create_solver<0,32>(net_count, sname); - } - else - if (net_count <= 64) - { - ms = create_solver<0,64>(net_count, sname); - } - else - if (net_count <= 128) - { - ms = create_solver<0,128>(net_count, sname); - } - else - { - log().fatal(MF_1_NETGROUP_SIZE_EXCEEDED_1, 128); - ms = nullptr; /* tease compilers */ - } + pool_owned_ptr<matrix_solver_t> ms; + std::size_t net_count = grp.size(); + pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size()); - break; - } + switch (net_count) + { + #if 1 + case 1: + ms = pool().make_poolptr<matrix_solver_direct1_t<double>>(state(), sname, &m_params); + break; + case 2: + ms = pool().make_poolptr<matrix_solver_direct2_t<double>>(state(), sname, &m_params); + break; + case 3: + ms = create_solver<double, 3>(3, sname); + break; + case 4: + ms = create_solver<double, 4>(4, sname); + break; + case 5: + ms = create_solver<double, 5>(5, sname); + break; + case 6: + ms = create_solver<double, 6>(6, sname); + break; + case 7: + ms = create_solver<double, 7>(7, sname); + break; + case 8: + ms = create_solver<double, 8>(8, sname); + break; + case 9: + ms = create_solver<double, 9>(9, sname); + break; + case 10: + ms = create_solver<double, 10>(10, sname); + break; + #if 0 + case 11: + ms = create_solver<double, 11>(11, sname); + break; + case 12: + ms = create_solver<double, 12>(12, sname); + break; + case 15: + ms = create_solver<double, 15>(15, sname); + break; + case 31: + ms = create_solver<double, 31>(31, sname); + break; + case 35: + ms = create_solver<double, 35>(35, sname); + break; + case 43: + ms = create_solver<double, 43>(43, sname); + break; + case 49: + ms = create_solver<double, 49>(49, sname); + break; + #endif + #if 1 + case 86: + ms = create_solver<double,86>(86, sname); + break; + #endif + #endif + default: + log().warning(MW_1_NO_SPECIFIC_SOLVER, net_count); + if (net_count <= 8) + { + ms = create_solver<double, -8>(net_count, sname); + } + else if (net_count <= 16) + { + ms = create_solver<double, -16>(net_count, sname); + } + else if (net_count <= 32) + { + ms = create_solver<double, -32>(net_count, sname); + } + else + if (net_count <= 64) + { + ms = create_solver<double, -64>(net_count, sname); + } + else + if (net_count <= 128) + { + ms = create_solver<double, -128>(net_count, sname); + } + else + { + log().fatal(MF_1_NETGROUP_SIZE_EXCEEDED_1, 128); + return; /* tease compilers */ + } + break; + } - // FIXME ... - ms->setup(grp); + // FIXME ... + ms->setup(grp); - log().verbose("Solver {1}", ms->name()); - log().verbose(" ==> {2} nets", grp.size()); - log().verbose(" has {1} elements", ms->has_dynamic_devices() ? "dynamic" : "no dynamic"); - log().verbose(" has {1} elements", ms->has_timestep_devices() ? "timestep" : "no timestep"); - for (auto &n : grp) - { - log().verbose("Net {1}", n->name()); - for (const auto &pcore : n->m_core_terms) + log().verbose("Solver {1}", ms->name()); + log().verbose(" ==> {2} nets", grp.size()); + log().verbose(" has {1} elements", ms->has_dynamic_devices() ? "dynamic" : "no dynamic"); + log().verbose(" has {1} elements", ms->has_timestep_devices() ? "timestep" : "no timestep"); + for (auto &n : grp) { - log().verbose(" {1}", pcore->name()); + log().verbose("Net {1}", n->name()); + for (const auto &pcore : n->core_terms()) + { + log().verbose(" {1}", pcore->name()); + } } - } - m_mat_solvers.push_back(std::move(ms)); + m_mat_solvers_all.push_back(ms.get()); + if (ms->has_timestep_devices()) + m_mat_solvers_timestepping.push_back(ms.get()); + + m_mat_solvers.emplace_back(std::move(ms)); + } } -} -void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp) -{ - for (auto & s : m_mat_solvers) + void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp) { - auto r = s->create_solver_code(); - mp[r.first] = r.second; // automatically overwrites identical names + for (auto & s : m_mat_solvers) + { + auto r = s->create_solver_code(); + mp[r.first] = r.second; // automatically overwrites identical names + } } -} - NETLIB_DEVICE_IMPL(solver) + NETLIB_DEVICE_IMPL(solver, "SOLVER", "FREQ") - } //namespace devices +} // namespace devices } // namespace netlist |