summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/solver/nld_solver.cpp
diff options
context:
space:
mode:
author andreasnaive <andreasnaive@gmail.com>2019-03-25 23:13:40 +0100
committer andreasnaive <andreasnaive@gmail.com>2019-03-25 23:13:40 +0100
commitb380514764cf857469bae61c11143a19f79a74c5 (patch)
tree63c8012e262618f08a332da31dd714281aa2c5ed /src/lib/netlist/solver/nld_solver.cpp
parentc24473ddff715ecec2e258a6eb38960cf8c8e98e (diff)
Revert "conflict resolution (nw)"
This reverts commit c24473ddff715ecec2e258a6eb38960cf8c8e98e, reversing changes made to 009cba4fb8102102168ef32870892438327f3705.
Diffstat (limited to 'src/lib/netlist/solver/nld_solver.cpp')
-rw-r--r--src/lib/netlist/solver/nld_solver.cpp641
1 files changed, 318 insertions, 323 deletions
diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp
index 4734cc3624d..cae76caab1a 100644
--- a/src/lib/netlist/solver/nld_solver.cpp
+++ b/src/lib/netlist/solver/nld_solver.cpp
@@ -31,398 +31,393 @@
#pragma GCC optimize "ivopts"
#endif
-#include "netlist/nl_lists.h"
-#include "netlist/nl_factory.h"
+#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 "nld_matrix_solver.h"
+
+#if 1
#include "nld_ms_direct.h"
-#include "nld_ms_direct1.h"
-#include "nld_ms_direct2.h"
#include "nld_ms_gcr.h"
-#include "nld_ms_gmres.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_sor.h"
#include "nld_ms_sor_mat.h"
-#include "nld_ms_w.h"
-#include "nld_solver.h"
-#include "plib/pomp.h"
-
-#include <algorithm>
-#include <cmath>
+#include "nld_ms_gmres.h"
namespace netlist
{
-namespace devices
-{
+ namespace devices
+ {
- // ----------------------------------------------------------------------------------------
- // solver
- // ----------------------------------------------------------------------------------------
- NETLIB_RESET(solver)
- {
- for (auto &s : m_mat_solvers)
- s->reset();
- }
- void NETLIB_NAME(solver)::stop()
- {
- for (auto &s : m_mat_solvers)
- s->log_stats();
- }
+// ----------------------------------------------------------------------------------------
+// solver
+// ----------------------------------------------------------------------------------------
- NETLIB_UPDATE(solver)
- {
- if (m_params.m_dynamic_ts)
- return;
+NETLIB_RESET(solver)
+{
+ for (std::size_t i = 0; i < m_mat_solvers.size(); i++)
+ m_mat_solvers[i]->do_reset();
+}
- 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));
+void NETLIB_NAME(solver)::stop()
+{
+ for (std::size_t i = 0; i < m_mat_solvers.size(); i++)
+ m_mat_solvers[i]->log_stats();
+}
- std::size_t nthreads = std::min(static_cast<std::size_t>(m_parallel()), plib::omp::get_max_threads());
+NETLIB_NAME(solver)::~NETLIB_NAME(solver)()
+{
+}
- std::vector<matrix_solver_t *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_timestepping);
+NETLIB_UPDATE(solver)
+{
+ if (m_params.m_dynamic_ts)
+ return;
- 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);
- }
+ /* 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));
- for (auto & solver : solvers)
- solver->update_inputs();
+ 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;
- /* 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));
- }
+ 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();
+
+ for (auto & solver : m_mat_solvers)
+ if (solver->has_timestep_devices() || force_solve)
+ solver->update_inputs();
- template <class C>
- pool_owned_ptr<matrix_solver_t> create_it(netlist_state_t &nl, pstring name, solver_parameters_t &params, std::size_t size)
+ /* step circuit */
+ if (!m_Q_step.net().is_queued())
{
- return pool().make_poolptr<C>(nl, name, &params, size);
+ m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_max_timestep));
}
+}
- template <typename FT, int SIZE>
- pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername)
+template <class C>
+std::unique_ptr<matrix_solver_t> create_it(netlist_t &nl, pstring name, solver_parameters_t &params, std::size_t size)
+{
+ typedef C solver;
+ return plib::make_unique<solver>(nl, name, &params, 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()))
{
- 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")
- {
- /* 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
- {
- log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method());
- return pool_owned_ptr<matrix_solver_t>();
- }
+ 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);
}
-
- template <typename FT, int SIZE>
- pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver_x(std::size_t size, const pstring &solvername)
+ else if (pstring("MAT_CR").equals(m_method()))
{
- if (SIZE > 0)
+ if (size > 0) // GCR always outperforms MAT solver
{
- if (size == SIZE)
- return create_solver<FT, SIZE>(size, solvername);
- else
- return this->create_solver_x<FT, SIZE-1>(size, solvername);
+ typedef matrix_solver_GCR_t<m_N,storage_N> solver_mat;
+ return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
}
else
{
- if (size * 2 > -SIZE )
- return create_solver<FT, SIZE>(size, solvername);
- else
- return this->create_solver_x<FT, SIZE / 2>(size, solvername);
+ typedef matrix_solver_direct_t<m_N,storage_N> solver_mat;
+ return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
}
}
-
- struct net_splitter
+ 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
+ {
+ log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method());
+ return nullptr;
+ }
+}
- bool already_processed(const analog_net_t &n) const
- {
- /* no need to process rail nets - these are known variables */
- if (n.isRailNet())
+struct net_splitter
+{
+
+ bool already_processed(analog_net_t *n)
+ {
+ if (n->isRailNet())
+ return true;
+ for (auto & grp : groups)
+ if (plib::container::contains(grp, n))
return true;
- /* if it's already processed - no need to continue */
- for (auto & grp : groups)
- if (plib::container::contains(grp, &n))
- return true;
- return false;
- }
+ return false;
+ }
- void process_net(analog_net_t &n)
+ 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)
{
- /* 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())
+ if (p->is_type(detail::terminal_type::TERMINAL))
{
- /* 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);
- }
+ 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);
}
}
+ }
- void run(netlist_state_t &netlist)
+ void run(netlist_t &netlist)
+ {
+ for (auto & net : netlist.m_nets)
{
- for (auto & net : netlist.nets())
+ netlist.log().debug("processing {1}\n", net->name());
+ if (!net->isRailNet() && net->num_cons() > 0)
{
- netlist.log().debug("processing {1}\n", net->name());
- if (!net->isRailNet() && net->num_cons() > 0)
+ 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(" ==> 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);
- }
+ groups.push_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()
+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)
{
- 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_use_gabs = m_use_gabs();
- m_params.m_use_linear_prediction = m_use_linear_prediction();
-
+ m_params.m_max_timestep *= 1;//NL_FCONST(1000.0);
+ }
+ else
+ {
+ m_params.m_min_timestep = m_params.m_max_timestep;
+ }
- 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;
- }
+ //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::)
- //m_params.m_max_timestep = std::max(m_params.m_max_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();
- // 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();
+ log().verbose("Scanning net groups ...");
+ // determine net groups
- log().verbose("Scanning net groups ...");
- // determine net groups
+ net_splitter splitter;
- net_splitter splitter;
+ splitter.run(netlist());
- splitter.run(state());
+ // 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());
- // setup the solvers
- log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size());
- for (auto & grp : splitter.groups)
+ switch (net_count)
{
- pool_owned_ptr<matrix_solver_t> ms;
- std::size_t net_count = grp.size();
- pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size());
+#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 */
+ }
- 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;
- }
+ 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("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("Net {1}", n->name());
- for (const auto &pcore : n->core_terms())
- {
- log().verbose(" {1}", pcore->name());
- }
+ log().verbose(" {1}", pcore->name());
}
-
- 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));
}
+
+ m_mat_solvers.push_back(std::move(ms));
}
+}
- void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp)
+void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp)
+{
+ for (auto & s : m_mat_solvers)
{
- for (auto & s : m_mat_solvers)
- {
- auto r = s->create_solver_code();
- mp[r.first] = r.second; // automatically overwrites identical names
- }
+ auto r = s->create_solver_code();
+ mp[r.first] = r.second; // automatically overwrites identical names
}
+}
- NETLIB_DEVICE_IMPL(solver, "SOLVER", "FREQ")
+ NETLIB_DEVICE_IMPL(solver)
-} // namespace devices
+ } //namespace devices
} // namespace netlist