netlist: improve readability. (nw)

The purpose here is to make clear what is actually done and to reduce
usage of calls to update.
This commit is contained in:
couriersud 2020-04-25 13:01:16 +02:00
parent 9c756b09d8
commit f5fad035de
15 changed files with 69 additions and 53 deletions

View File

@ -463,7 +463,6 @@ namespace analog
}
protected:
// NETLIB_UPDATEI() { NETLIB_NAME(twoterm)::update(time); }
NETLIB_RESETI()
{
@ -513,7 +512,6 @@ namespace analog
protected:
//NETLIB_UPDATEI() { NETLIB_NAME(twoterm)::update(time); }
NETLIB_RESETI()
{
NETLIB_NAME(twoterm)::reset();

View File

@ -69,7 +69,7 @@ namespace netlist
if (R > nlconst::zero() && (m_last != new_state))
{
m_last = new_state;
m_R.update();
m_R.solve_now();
m_R.set_R(R);
m_R.solve_later();
}

View File

@ -43,7 +43,7 @@ namespace netlist { namespace devices {
NETLIB_UPDATE(CD4316_GATE)
{
m_R.update();
m_R.solve_now();
if (m_S() && !m_E())
m_R.set_R(m_base_r());
else

View File

@ -106,7 +106,7 @@ namespace netlist
// We only need to update the net first if this is a time stepping net
if (m_is_timestep)
m_RV.update();
m_RV.solve_now();
m_RV.set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
m_RV.solve_later(NLTIME_FROM_NS(1));
}

View File

@ -196,13 +196,13 @@ namespace netlist
if (m_last_out && !out)
{
m_RDIS.update();
m_RDIS.solve_now();
m_OUT.push(m_R3.m_N());
m_RDIS.set_R(nlconst::magic(R_ON));
}
else if (!m_last_out && out)
{
m_RDIS.update();
m_RDIS.solve_now();
// FIXME: Should be delayed by 100ns
m_OUT.push(m_R1.m_P());
m_RDIS.set_R(nlconst::magic(R_OFF));

View File

@ -96,7 +96,7 @@ namespace netlist
{
m_last_state = 0;
if (m_is_timestep)
m_RVO.update();
m_RVO.solve_now();
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROH()), m_model.m_VOH, nlconst::zero());
m_RVO.solve_later();
}
@ -107,7 +107,7 @@ namespace netlist
{
m_last_state = 1;
if (m_is_timestep)
m_RVO.update();
m_RVO.solve_now();
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
m_RVO.solve_later();
}

View File

@ -161,7 +161,7 @@ namespace netlist
// We only need to update the net first if this is a time stepping net
if (m_is_timestep)
{
m_RN.update(); // RN, RP are connected ...
m_RN.solve_now(); // RN, RP are connected ...
}
if (state)
{

View File

@ -816,7 +816,7 @@ namespace netlist
// Nets may belong to railnets which do not have a solver attached
if (this->has_net())
if (net().solver() != nullptr)
net().solver()->update_forced();
net().solver()->solve_now();
}
void terminal_t::schedule_solve_after(netlist_time after) noexcept

View File

@ -118,8 +118,8 @@
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
#ifndef NL_USE_FLOAT_MATRIX
#define NL_USE_FLOAT_MATRIX (NL_USE_ACADEMIC_SOLVERS)
//#define NL_USE_FLOAT_MATRIX 1
//#define NL_USE_FLOAT_MATRIX (NL_USE_ACADEMIC_SOLVERS)
#define NL_USE_FLOAT_MATRIX 1
#endif
/// \brief Support long double type for matrix calculations.
@ -127,8 +127,8 @@
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
#ifndef NL_USE_LONG_DOUBLE_MATRIX
#define NL_USE_LONG_DOUBLE_MATRIX (NL_USE_ACADEMIC_SOLVERS)
//#define NL_USE_LONG_DOUBLE_MATRIX 1
//#define NL_USE_LONG_DOUBLE_MATRIX (NL_USE_ACADEMIC_SOLVERS)
#define NL_USE_LONG_DOUBLE_MATRIX 1
#endif
//============================================================

View File

@ -947,7 +947,7 @@ void setup_t::resolve_inputs()
detail::core_terminal_t *t1 = find_terminal(t1s);
detail::core_terminal_t *t2 = find_terminal(t2s);
if (connect(*t1, *t2))
m_links.erase(m_links.begin() + i);
m_links.erase(m_links.begin() + static_cast<std::ptrdiff_t>(i));
else
i++;
}

View File

@ -412,13 +412,11 @@ namespace solver
}
}
// update_forced is called from within param_update
//
// this should only occur outside of execution and thus
// using time should be safe.
void matrix_solver_t::update_forced()
void matrix_solver_t::solve_now()
{
// this should only occur outside of execution and thus
// using time should be safe.
const netlist_time new_timestep = solve(exec().time());
plib::unused_var(new_timestep);
@ -487,7 +485,11 @@ namespace solver
this->store();
}
return compute_next_timestep(delta.as_fp<nl_fptype>());
if (m_params.m_dynamic_ts)
return compute_next_timestep(delta.as_fp<nl_fptype>(), m_params.m_max_timestep);
return netlist_time::from_fp(m_params.m_max_timestep);
}
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept

View File

@ -194,7 +194,13 @@ namespace solver
std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); }
std::size_t timestep_device_count() const noexcept { return m_step_funcs.size(); }
void update_forced();
/// \brief Immediately solve system at current time
///
/// This should only be called from update and update_param events.
/// It's purpose is to bring voltage values to the current timestep.
/// This will be called BEFORE updating object properties.
void solve_now();
void update_after(netlist_time after) noexcept
{
m_Q_sync.net().toggle_and_push_to_queue(after);
@ -224,7 +230,7 @@ namespace solver
const solver_parameters_t *params);
virtual void vsolve_non_dynamic() = 0;
virtual netlist_time compute_next_timestep(nl_fptype cur_ts) = 0;
virtual netlist_time compute_next_timestep(nl_fptype cur_ts, nl_fptype max_ts) = 0;
virtual bool check_err() = 0;
virtual void store() = 0;
@ -402,13 +408,26 @@ namespace solver
return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim;
}
#if 1
void store() override
{
const std::size_t iN = size();
for (std::size_t i = 0; i < iN; i++)
this->m_terms[i].setV(m_new_V[i]);
}
#else
// global tanh damping (4.197)
// partially cures the symptoms but not the cause
void store() override
{
const std::size_t iN = size();
for (std::size_t i = 0; i < iN; i++)
{
auto oldV = this->m_terms[i].template getV<nl_fptype>();
this->m_terms[i].setV(oldV + 0.02 * plib::tanh((m_new_V[i]-oldV)*50.0));
}
}
#endif
bool check_err() override
{
// NOTE: Ideally we should also include currents (RHS) here. This would
@ -429,38 +448,35 @@ namespace solver
return false;
}
netlist_time compute_next_timestep(const nl_fptype cur_ts) override
netlist_time compute_next_timestep(nl_fptype cur_ts, nl_fptype max_ts) override
{
nl_fptype new_solver_timestep = m_params.m_max_timestep;
nl_fptype new_solver_timestep(max_ts);
if (m_params.m_dynamic_ts)
for (std::size_t k = 0; k < size(); k++)
{
for (std::size_t k = 0; k < size(); k++)
{
const auto &t = m_terms[k];
const auto v(t.template getV<nl_fptype>());
// avoid floating point exceptions
const nl_fptype DD_n = std::max(-fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),
std::min(+fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),(v - m_last_V[k])));
const auto &t = m_terms[k];
const auto v(t.template getV<nl_fptype>());
// avoid floating point exceptions
const nl_fptype DD_n = std::max(-fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),
std::min(+fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),(v - m_last_V[k])));
m_last_V[k] = v;
const nl_fptype hn = cur_ts;
m_last_V[k] = v;
const nl_fptype hn = cur_ts;
//printf("%g %g %g %g\n", DD_n, hn, t.m_DD_n_m_1, t.m_h_n_m_1);
nl_fptype DD2 = (DD_n / hn - m_DD_n_m_1[k] / m_h_n_m_1[k]) / (hn + m_h_n_m_1[k]);
nl_fptype new_net_timestep(0);
//printf("%g %g %g %g\n", DD_n, hn, t.m_DD_n_m_1, t.m_h_n_m_1);
nl_fptype DD2 = (DD_n / hn - m_DD_n_m_1[k] / m_h_n_m_1[k]) / (hn + m_h_n_m_1[k]);
nl_fptype new_net_timestep(0);
m_h_n_m_1[k] = hn;
m_DD_n_m_1[k] = DD_n;
if (plib::abs(DD2) > fp_constants<nl_fptype>::TIMESTEP_MINDIV()) // avoid div-by-zero
new_net_timestep = plib::sqrt(m_params.m_dynamic_lte / plib::abs(nlconst::magic(0.5)*DD2));
else
new_net_timestep = m_params.m_max_timestep;
m_h_n_m_1[k] = hn;
m_DD_n_m_1[k] = DD_n;
if (plib::abs(DD2) > fp_constants<nl_fptype>::TIMESTEP_MINDIV()) // avoid div-by-zero
new_net_timestep = plib::sqrt(m_params.m_dynamic_lte / plib::abs(nlconst::magic(0.5)*DD2));
else
new_net_timestep = m_params.m_max_timestep;
new_solver_timestep = std::min(new_net_timestep, new_solver_timestep);
}
new_solver_timestep = std::max(new_solver_timestep, m_params.m_min_timestep);
new_solver_timestep = std::min(new_net_timestep, new_solver_timestep);
}
new_solver_timestep = std::max(new_solver_timestep, m_params.m_min_timestep);
// FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
return std::max(netlist_time::from_fp(new_solver_timestep), netlist_time::quantum() * 2);

View File

@ -106,7 +106,7 @@ namespace solver
for (std::size_t k = 0; k < iN; k++)
{
this->m_new_V[k] = this->m_terms[k].template getV<float_type>();
this->m_new_V[k] = static_cast<float_type>(this->m_terms[k].getV());
}
const auto accuracy(static_cast<float_type>(this->m_params.m_accuracy));

View File

@ -80,7 +80,7 @@ namespace solver
const nl_fptype * const Idr = this->m_Idrn[k];
auto other_cur_analog = this->m_connected_net_Vn[k];
this->m_new_V[k] = this->m_terms[k].template getV<float_type>();
this->m_new_V[k] = static_cast<float_type>(this->m_terms[k].getV());
for (std::size_t i = 0; i < term_count; i++)
{

View File

@ -101,7 +101,7 @@ namespace solver
#endif
for (std::size_t k = 0; k < iN; k++)
this->m_new_V[k] = this->m_terms[k].template getV<FT>();
this->m_new_V[k] = static_cast<float_type>(this->m_terms[k].getV());
do {
resched = false;