bump to -rc12
[gnucap-felix.git] / lib / e_compon.cc
blob97cfe1837557c187fb0ca42a4c4c6971ce45eb53
1 /*$Id: e_compon.cc 2016/03/23 al $ -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * Base class for elements of a circuit
24 #include "u_lang.h"
25 #include "e_model.h"
26 #include "e_elemnt.h"
27 #include "io_trace.h"
28 #include "io_misc.h"
30 #include <typeinfo>
31 using namespace std;
33 /*--------------------------------------------------------------------------*/
34 using notstd::to_lower;
35 using std::string;
36 /*--------------------------------------------------------------------------*/
37 using notstd::to_lower;
38 using std::string;
39 /*--------------------------------------------------------------------------*/
40 COMMON_COMPONENT::COMMON_COMPONENT(const COMMON_COMPONENT& p)
41 :CKT_BASE(p),
42 _tnom_c(p._tnom_c),
43 _dtemp(p._dtemp),
44 _temp_c(p._temp_c),
45 _mfactor(p._mfactor),
46 _value(p._value),
47 _modelname(p._modelname),
48 _model(p._model),
49 _attach_count(0)
51 trace1(("COMMON_COMPONENT copy, modelname: "+p._modelname), hp(_model) );
53 /*--------------------------------------------------------------------------*/
54 COMMON_COMPONENT::COMMON_COMPONENT(int c)
55 :CKT_BASE(),
56 _tnom_c(NOT_INPUT),
57 _dtemp(0),
58 _temp_c(NOT_INPUT),
59 _mfactor(1),
60 _value(0),
61 _modelname(""), // !
62 _model(0),
63 _attach_count(c)
65 trace2("COMMON_COMPONENT::COMMON_COMPONENT"+ _modelname, c, hp(this));
67 /*--------------------------------------------------------------------------*/
68 COMMON_COMPONENT::~COMMON_COMPONENT()
70 assert(_attach_count == 0 || _attach_count == CC_STATIC);
72 /*--------------------------------------------------------------------------*/
73 // void COMPONENT::attach_common(COMMON_COMPONENT*c) {
74 // COMMON_COMPONENT::attach_common(c,&_common);}
75 /*--------------------------------------------------------------------------*/
76 void COMMON_COMPONENT::attach_common(COMMON_COMPONENT*c, COMMON_COMPONENT**to)
78 assert(to);
79 if (c == *to) {
80 // The new and old are the same object. Do nothing.
81 }else if (!c) { untested();
82 // There is no new common. probably a simple element
83 detach_common(to);
84 }else if (!*to) {
85 // No old one, but have a new one.
86 ++(c->_attach_count);
87 *to = c;
88 trace1("COMMON_COMPONENT::attach_common attached new ", hp(c) );
89 // trace2( c->modelname(), c->attach_count(), hp(c));
90 }else if (*c != **to) {
91 // They are different, usually by edit.
92 trace1("different... "+ c->name() + " " + c->modelname() , c->_attach_count );
93 detach_common(to);
94 ++(c->_attach_count);
95 *to = c;
96 }else if (c->_attach_count == 0) {
97 // The new and old are identical.
98 // Use the old one.
99 // The new one is not used anywhere, so throw it away.
100 trace1("COMMON_COMPONENT::attach_common, equal and c unused, deleting", hp(c));
101 delete c;
102 }else{ untested();
103 trace0("COMMON_COMPONENT::attach_common same twice");
104 untested();
105 // The new and old are identical.
106 // Use the old one.
107 // The new one is also used somewhere else, so keep it.
110 /*--------------------------------------------------------------------------*/
111 void COMMON_COMPONENT::detach_common(COMMON_COMPONENT** from)
113 assert(from);
114 if (*from) {
115 assert((**from)._attach_count > 0);
116 //assert((**from)._attach_count != CC_STATIC );
117 --((**from)._attach_count);
118 if ((**from)._attach_count == 0) {
119 delete *from;
120 }else{
122 *from = NULL;
123 }else{
126 /*--------------------------------------------------------------------------*/
127 void COMMON_COMPONENT::attach_model(const COMPONENT* d)const
129 assert(d);
130 trace1("COMMON_COMPONENT::attach_model to", d->short_label());
132 _model = d->find_model(modelname());
133 assert(_model);
134 trace2("COMMON_COMPONENT::attach_model attached ", hp(_model), hp(this) );
136 /*--------------------------------------------------------------------------*/
137 void COMMON_COMPONENT::parse_modelname(CS& cmd)
139 set_modelname(cmd.ctos(TOKENTERM));
140 trace0(("COMMON_COMPONENT::parse_modelname " + _modelname).c_str() );
142 /*--------------------------------------------------------------------------*/
143 // called only by COMMON_COMPONENT::parse_obsolete
144 bool COMMON_COMPONENT::parse_param_list(CS& cmd)
146 trace0(("COMMON_COMPONENT::parse_param_list " + cmd.tail()).c_str() );
147 unsigned start = cmd.cursor();
148 unsigned here = cmd.cursor();
150 parse_params_obsolete_callback(cmd); //BUG//callback
151 }while (cmd.more() && !cmd.stuck(&here));
152 return cmd.gotit(start);
154 /*--------------------------------------------------------------------------*/
155 void COMMON_COMPONENT::parse_common_obsolete_callback(CS& cmd) //used
157 trace1("COMMON_COMPONENT::parse_common_obsolete_callback ", cmd.tail() );
158 if (cmd.skip1b('(')) {
159 // start with a paren
160 unsigned start = cmd.cursor();
161 parse_param_list(cmd);
162 if (cmd.gotit(start)) { // ( params ( ....
163 // named args before num list
164 if (cmd.skip1b('(')) { // ( params ( list ) params )
165 parse_numlist(cmd);
166 if (!cmd.skip1b(')')) {untested();
167 cmd.warn(bWARNING, "need )");
168 }else{
170 }else{ // ( params list params )
171 parse_numlist(cmd); //BUG//
173 parse_param_list(cmd);
174 if (!cmd.skip1b(')')) {untested();
175 cmd.warn(bWARNING, "need )");
176 }else{
178 }else{
179 // no named args before num list
180 // but there's a paren
181 // not sure whether it belongs to all args or to num list
182 if (cmd.skip1b('(')) { // ( ( list ) params )
183 // two parens
184 parse_numlist(cmd);
185 if (!cmd.skip1b(')')) {untested();
186 cmd.warn(bWARNING, "need )");
187 }else{
189 parse_param_list(cmd);
190 if (!cmd.skip1b(')')) {untested();
191 cmd.warn(bWARNING, "need )");
192 }else{
194 }else{ // ( list ...
195 // only one paren
196 parse_numlist(cmd);
197 if (cmd.skip1b(')')) { // ( list ) params
198 // assume it belongs to num list
199 // and named params follow
200 parse_param_list(cmd);
201 }else{ // ( list params )
202 // assume it belongs to all args
203 parse_param_list(cmd);
204 if (!cmd.skip1b(')')) {
205 cmd.warn(bWARNING, "need )");
206 }else{
211 }else{
212 // does not start with a paren
213 unsigned start = cmd.cursor();
214 parse_param_list(cmd);
215 if (cmd.gotit(start)) {
216 if (cmd.skip1b('(')) { // params ( list ) params
217 parse_numlist(cmd);
218 if (!cmd.skip1b(')')) {untested();
219 cmd.warn(bWARNING, "need )");
220 }else{
222 }else if (!(cmd.is_alpha())) { // params list params
223 parse_numlist(cmd);
224 }else{ // params (only)
226 }else{ // list params
227 assert(!(cmd.skip1b('(')));
228 parse_numlist(cmd);
230 parse_param_list(cmd);
231 if (cmd.skip1b(')')) {
232 cmd.warn(bWARNING, start, "need (");
233 }else{
237 /*--------------------------------------------------------------------------*/
238 void COMMON_COMPONENT::print_common_obsolete_callback(OMSTREAM& o, LANGUAGE* lang)const
240 trace0(("COMMON_COMPONENT::print_common_obsolete_callback "+ _modelname).c_str());
241 assert(lang);
242 print_pair(o, lang, "tnom", _tnom_c, _tnom_c.has_hard_value());
243 print_pair(o, lang, "dtemp",_dtemp, _dtemp.has_hard_value());
244 print_pair(o, lang, "temp", _temp_c, _temp_c.has_hard_value());
245 print_pair(o, lang, "m", _mfactor, _mfactor.has_hard_value());
247 /*--------------------------------------------------------------------------*/
248 void COMMON_COMPONENT::set_param_by_index(int i, std::string& Value, int Offset)
250 switch (i) {
251 case 0:untested(); _tnom_c = Value; break;
252 case 1:untested(); _dtemp = Value; break;
253 case 2:untested(); _temp_c = Value; break;
254 case 3: _mfactor = Value; break;
255 default:untested();
256 throw Exception_Too_Many(unsigned(i), 3u, Offset); break;
259 /*--------------------------------------------------------------------------*/
260 bool COMMON_COMPONENT::param_is_printable(int i)const
262 switch (i) {
263 case 0: return _tnom_c.has_hard_value();
264 case 1: return _dtemp.has_hard_value();
265 case 2: return _temp_c.has_hard_value();
266 case 3: return _mfactor.has_hard_value();
267 default:untested(); return false;
270 /*--------------------------------------------------------------------------*/
271 std::string COMMON_COMPONENT::param_name(int i)const
273 switch (i) {
274 case 0:itested(); return "tnom";
275 case 1:itested(); return "dtemp";
276 case 2:itested(); return "temp";
277 case 3: return "m";
278 default:untested(); return "";
281 /*--------------------------------------------------------------------------*/
282 std::string COMMON_COMPONENT::param_name(int i, int j)const
283 {itested();
284 return (j==0) ? param_name(i) : "";
286 /*--------------------------------------------------------------------------*/
287 std::string COMMON_COMPONENT::param_value(int i)const
289 switch (i) {
290 case 0:untested(); return _tnom_c.string();
291 case 1:untested(); return _dtemp.string();
292 case 2:untested(); return _temp_c.string();
293 case 3: return _mfactor.string();
294 default:untested(); return "";
297 /*--------------------------------------------------------------------------*/
298 void COMMON_COMPONENT::precalc_last(const CARD_LIST* Scope)
300 assert(Scope);
301 _tnom_c.e_val(OPT::tnom_c, Scope);
302 _dtemp.e_val(0., Scope);
303 _temp_c.e_val(_sim->_temp_c + _dtemp, Scope);
304 _mfactor.e_val(1, Scope);
305 _value.e_val(0, Scope);
307 /*--------------------------------------------------------------------------*/
308 void COMMON_COMPONENT::tt_commit(ELEMENT*x)const
309 { untested();
310 assert(_model);
311 _model->do_tt_commit(x);
313 /*--------------------------------------------------------------------------*/
314 void COMMON_COMPONENT::tr_eval(ELEMENT*x)const
315 { untested();
316 assert(_model);
318 //printf("typeid(_model): %s", typeid(_model).name());
320 _model->tr_eval(x);
322 /*--------------------------------------------------------------------------*/
323 void COMMON_COMPONENT::ac_eval(ELEMENT*x)const
324 {untested(); // bug?
325 assert(_model);
326 _model->ac_eval(x);
328 /*--------------------------------------------------------------------------*/
329 bool COMMON_COMPONENT::operator==(const COMMON_COMPONENT& x)const
331 return (_modelname == x._modelname
332 && _model == x._model
333 && _tnom_c == x._tnom_c
334 && _dtemp == x._dtemp
335 && _temp_c == x._temp_c
336 && _mfactor == x._mfactor
337 && _value == x._value);
339 /*--------------------------------------------------------------------------*/
340 map<string, PARA_BASE COMMON_COMPONENT::*> COMMON_COMPONENT::_param_dict
341 = boost::assign::map_list_of
342 ("tnom", (PARA_BASE COMMON_COMPONENT::*) (&COMMON_COMPONENT::_tnom_c))
343 ("dtemp", (PARA_BASE COMMON_COMPONENT::*) (&COMMON_COMPONENT::_dtemp))
344 ("temp", (PARA_BASE COMMON_COMPONENT::*) (&COMMON_COMPONENT::_temp_c))
345 ("m", (PARA_BASE COMMON_COMPONENT::*) (&COMMON_COMPONENT::_mfactor));
346 /*--------------------------------------------------------------------------*/
347 void COMMON_COMPONENT::set_param_by_name(std::string Name, std::string Value)
349 PARA_BASE COMMON_COMPONENT::* x = (OPT::case_insensitive)?
350 (_param_dict[to_lower(Name)]) : (_param_dict[Name]);
351 if(x) {
352 PARA_BASE* p = &(this->*x);
353 *p = Value;
354 return;
357 if (has_parse_params_obsolete_callback()) {
358 std::string args(Name + "=" + Value);
359 CS cmd(CS::_STRING, args); //obsolete_callback
360 trace3("COMMON_COMPONENT::set_param_by_name", Name, Value, cmd.fullstring());
361 bool ok = parse_params_obsolete_callback(cmd); //BUG//callback
362 if (!ok) {untested();
363 throw Exception_No_Match(Name);
364 }else{
366 }else if (Umatch(Name, "tnom")) { untested();
367 _tnom_c = Value;
368 }else if (Umatch(Name, "dtemp")) { untested();
369 _dtemp = Value;
370 }else if (Umatch(Name, "temp")) { untested();
371 _temp_c = Value;
372 }else if (Umatch(Name, "m")) {
373 _mfactor = Value;
374 }else{
375 //BUG// ugly linear search
376 for (int i = param_count() - 1; i >= 0; --i) {
377 for (int j = 0; param_name(i,j) != ""; ++j) {
378 if (Umatch(Name, param_name(i,j) + ' ')) {
379 cerr << typeid(this).name() << " linear search for " << Name << ": ";
380 incomplete();
381 set_param_by_index(i, Value, 0/*offset*/);
382 return; //success
383 }else{
384 //keep looking
388 throw Exception_No_Match(Name);
391 /*--------------------------------------------------------------------------*/
392 //BUG// This is a kluge for the spice_wrapper, to disable virtual functions.
393 // It is called during expansion only.
395 void COMMON_COMPONENT::Set_param_by_name(std::string Name, std::string Value)
396 {untested();
397 assert(!has_parse_params_obsolete_callback());
399 //BUG// ugly linear search
400 for (int i = COMMON_COMPONENT::param_count() - 1; i >= 0; --i) {untested();
401 for (int j = 0; COMMON_COMPONENT::param_name(i,j) != ""; ++j) {untested();
402 if (Umatch(Name, COMMON_COMPONENT::param_name(i,j) + ' ')) {untested();
403 COMMON_COMPONENT::set_param_by_index(i, Value, 0/*offset*/);
404 return; //success
405 }else{untested();
406 //keep looking
410 throw Exception_No_Match(Name);
412 /*--------------------------------------------------------------------------*/
413 bool COMMON_COMPONENT::parse_numlist(CS&)
415 return false;
417 /*--------------------------------------------------------------------------*/
418 bool COMMON_COMPONENT::parse_params_obsolete_callback(CS& cmd)
420 return ONE_OF
421 || Get(cmd, "tnom", &_tnom_c)
422 || Get(cmd, "dtemp", &_dtemp)
423 || Get(cmd, "temp", &_temp_c)
424 || Get(cmd, "m", &_mfactor)
425 || Get(cmd, "mfactor",&_mfactor)
428 /*--------------------------------------------------------------------------*/
429 /*--------------------------------------------------------------------------*/
430 COMPONENT::COMPONENT()
431 :CARD(),
432 _common(0),
433 _value(0),
434 _mfactor(1),
435 _mfactor_fixed(NOT_VALID),
436 _converged(false),
437 _q_for_eval(-1),
438 _time_by(),
439 _amps(0),
440 _adp(0)
442 trace1("COMPONENT::COMPONENT", long_label());
443 if (_sim) {
444 _sim->uninit();
445 } else {
448 /*--------------------------------------------------------------------------*/
449 COMPONENT::COMPONENT(const COMPONENT& p)
450 :CARD(p),
451 _common(0),
452 _value(p._value),
453 _mfactor(p._mfactor),
454 _mfactor_fixed(p._mfactor_fixed),
455 _converged(p._converged),
456 _q_for_eval(-1),
457 _time_by(p._time_by),
458 _amps(0),
459 _adp(0)
461 if (_sim) {
462 _sim->uninit();
463 } else { untested();
465 trace0("attaching common");
466 if(p._adp){
467 attach_adp(p._adp->clone());
469 attach_common(p._common);
470 assert(_common == p._common);
472 /*--------------------------------------------------------------------------*/
473 COMPONENT::~COMPONENT()
475 if (_amps) free (_amps);
476 detach_common();
477 if (_sim) {
478 _sim->uninit();
479 } else { itested();
482 /*--------------------------------------------------------------------------*/
483 bool COMPONENT::node_is_grounded(uint_t i)const
485 assert(_n);
486 assert(i != INVALID_NODE);
487 assert(i < net_nodes());
488 return _n[i].is_grounded();
490 /*--------------------------------------------------------------------------*/
491 bool COMPONENT::node_is_connected(uint_t i)const
493 assert(_n);
494 assert(i != INVALID_NODE);
495 if (i >= net_nodes()) {
496 trace3( "COMPONENT::node_is_connected", i, net_nodes(), _net_nodes );
497 assert(false);
499 return _n[i].is_connected();
501 /*--------------------------------------------------------------------------*/
502 void COMPONENT::set_port_by_name(std::string& int_name, std::string& ext_name)
504 for (uint_t i=0; i<max_nodes(); ++i) {
505 if (int_name == port_name(i)) {
506 set_port_by_index(i, ext_name);
507 return;
508 }else{
511 throw Exception_No_Match(int_name);
513 /*--------------------------------------------------------------------------*/
514 #ifdef DDO_TRACE
515 #include "e_cardlist.h"
516 #include "e_node.h"
517 #include "u_nodemap.h"
518 class NODE;
519 class NODE_MAP;
520 inline void trace_nodenames(const CARD_LIST* scope){
521 trace0("CARD_LIST tracing nodenames");
522 NODE_MAP* nm = scope->nodes();
523 for (NODE_MAP::const_iterator ni = nm->begin(); ni != nm->end(); ++ni) {
524 //NODE_BASE* n = (*ni).second;
525 string label = (*ni).first;
526 //trace2("CARD_LIST:... nodename ", label, n->user_number() );
529 #else
530 inline void trace_nodenames(const CARD_LIST*){}
531 #endif
532 /*--------------------------------------------------------------------------*/
533 void COMPONENT::set_port_by_index(uint_t num, std::string& ext_name)
535 if (num < max_nodes()) {
536 _n[num].new_node(ext_name, this);
537 trace1("COMPONENT::set_port_by_index", _n[num].t_());
538 if (num+1 > _net_nodes) {
539 // make the list bigger
540 _net_nodes = num+1;
541 }else{
542 // it's already big enough, probably assigning out of order
544 }else{
545 throw Exception_Too_Many(num+1, max_nodes(), 0/*offset*/);
547 trace_nodenames(scope());
549 /*--------------------------------------------------------------------------*/
550 void COMPONENT::set_port_to_ground(uint_t num)
552 if (num < max_nodes()) {
553 _n[num].set_to_ground(this);
554 if (num+1 > _net_nodes) {
555 _net_nodes = num+1;
556 }else{untested();
558 }else{untested();
559 throw Exception_Too_Many(num+1, max_nodes());
562 /*--------------------------------------------------------------------------*/
563 void COMPONENT::set_dev_type(const std::string& new_type)
565 trace1("COMPONENT::set_dev_type", new_type);
566 if (common()) {
567 if (new_type != dev_type()) {
568 COMMON_COMPONENT* c = common()->clone();
569 assert(c);
570 c->set_modelname(new_type);
571 attach_common(c);
572 }else{
574 }else{
575 CARD::set_dev_type(new_type);
578 /*--------------------------------------------------------------------------*/
579 void COMPONENT::print_args_obsolete_callback(OMSTREAM& o, LANGUAGE* lang)const
581 assert(lang);
582 assert(has_common());
583 trace0(("COMPONENT::print_args_obsolete_callback "+ short_label()).c_str());
584 common()->print_common_obsolete_callback(o, lang);
585 if(comment()!=""){ untested();
586 o << " ; " << comment();
587 }else{
590 /*--------------------------------------------------------------------------*/
591 void COMPONENT::deflate_common()
592 {untested();
593 unreachable();
594 trace0("COMPONENT::deflate_common");
595 if (has_common()) {untested();
596 COMMON_COMPONENT* deflated_common = mutable_common()->deflate();
597 if (deflated_common != common()) {untested();
598 attach_common(deflated_common);
599 }else{untested();
601 }else{untested();
602 unreachable();
605 /*--------------------------------------------------------------------------*/
606 void COMPONENT::expand()
608 CARD::expand();
609 if (has_common()) {
610 COMMON_COMPONENT* new_common = common()->clone();
611 new_common->expand(this);
612 COMMON_COMPONENT* deflated_common = new_common->deflate();
614 if ( deflated_common != common()) {
615 attach_common(deflated_common);
616 }else if ( deflated_common != new_common ) {
617 delete new_common;
618 }else{
619 untested();
621 }else{
623 trace1("COMPONENT::expand done", long_label());
625 /*--------------------------------------------------------------------------*/
626 void COMPONENT::precalc_first()
628 trace4("COMPONENT::precalc_first", long_label(), _value, *(scope()->params()), hp(mutable_common()));
629 CARD::precalc_first();
630 if (has_common()) {
631 try {
632 mutable_common()->precalc_first(scope());
633 }catch (Exception_Precalc& e) {untested();
634 trace0("COMPONENT::precalc_first exception...");
635 error(bWARNING, long_label() + ": " + e.message());
637 _mfactor = common()->mfactor();
638 }else{
641 //BUG// _mfactor must be in precalc_first
643 _mfactor.e_val(1, scope());
644 trace2("COMPONENT::precalc_first", long_label(), double(_mfactor));
645 if (const COMPONENT* o = prechecked_cast<const COMPONENT*>(owner())) {
646 _mfactor_fixed = o->mfactor() * _mfactor;
647 }else{
648 _mfactor_fixed = _mfactor;
650 trace4("COMPONENT::precalc_first done", long_label(), _mfactor_fixed, _value, common()?common()->value():-1.);
652 /*--------------------------------------------------------------------------*/
653 void COMPONENT::precalc_last()
655 CARD::precalc_last();
656 if (has_common()) {
657 trace1("COMPONENT::precalc_last", long_label());
658 try {
659 mutable_common()->precalc_last(scope());
660 }catch (Exception_Precalc& e) {
661 error(bWARNING, long_label() + ": " + e.message());
663 }else{
666 _value.e_val(0.,scope());
667 trace4("COMPONENT::precalc_last done", long_label(), _mfactor_fixed, _value, common()?common()->value():-1.);
669 /*--------------------------------------------------------------------------*/
670 void COMPONENT::map_nodes()
672 trace5("COMPONENT::map_nodes", long_label(), ext_nodes(), int_nodes(),
673 max_nodes(), net_nodes());
674 if(!is_device()){ unreachable();
675 return;
677 //assert(min_nodes() <= net_nodes());
678 assert(net_nodes() <= max_nodes());
679 //assert(ext_nodes() + int_nodes() == matrix_nodes());
681 for (uint_t ii = 0; ii < ext_nodes()+int_nodes(); ++ii) {
682 unsigned oldm = _n[ii].m_(); USE(oldm);
683 assert(_n[ii].t_() <= NODE::_sim->_total_nodes || _n[ii].t_()==INVALID_NODE || _n[ii].is_adp() );
684 _n[ii].map();
685 assert(_n[ii].m_() <= _sim->_total_nodes || _n[ii].m_() == INVALID_NODE || _n[ii].is_adp() );
686 unsigned user_number = (_n[ii].n_())? _n[ii].n_()->user_number(): 0; USE(user_number);
687 unsigned matrix_number = (_n[ii].n_())? _n[ii].n_()->matrix_number(): 0;
688 string node_label = (_n[ii].n_())? _n[ii].n_()->long_label(): "";
689 // matrix_number not initialized yet.
690 USE(user_number); USE(matrix_number);
691 trace5("COMPONENT::map_nodes done", long_label(), ii, _n[ii].t_(), _n[ii].m_(), _n[ii].is_adp() );
692 user_number = matrix_number = 0;
693 node_label="";
696 if (subckt()) {
697 subckt()->map_nodes();
698 }else{
701 /*--------------------------------------------------------------------------*/
702 void COMPONENT::tr_iwant_matrix()
704 if (is_device()) {
705 assert(matrix_nodes() == 0);
706 if (subckt()) {
707 subckt()->tr_iwant_matrix();
708 }else{ // untested();
710 }else{
713 /*--------------------------------------------------------------------------*/
714 void COMPONENT::ac_iwant_matrix()
716 if (is_device()) {
717 assert(matrix_nodes() == 0);
718 if (subckt()) {
719 subckt()->ac_iwant_matrix();
720 }else{ // untested();
722 }else{
725 /*--------------------------------------------------------------------------*/
726 /* set: set parameters, used in model building
728 void COMPONENT::set_parameters(const std::string& Label, CARD *Owner,
729 COMMON_COMPONENT *Common, double Value,
730 uint_t , hp_float_t [],
731 uint_t node_count, const node_t Nodes[])
733 trace6("COMPONENT::set_parameters", long_label(), hp(Common), hp(common()), max_nodes(), node_count, net_nodes());
734 set_label(Label);
735 set_owner(Owner);
736 set_value(Value);
737 attach_common(Common);
738 _net_nodes = node_count;
739 assert(node_count <= max_nodes());
741 if (node_count > net_nodes()) {
742 error(bDANGER, "net nodes problem in %s: only have %i, passed %i\n", long_label().c_str(), net_nodes(), node_count);
744 assert(node_count <= net_nodes());
746 trace0("COMPONENT::set_parameters copy nodes...");
747 notstd::copy_n(Nodes, node_count, _n);
749 for(uint_t i=0; i<node_count;i++){
750 trace6("COMPONENT::set_parameters", long_label(), i, Nodes[i].is_adp(), _n[i].is_adp(), _n[i].m_(), _n[i].t_());
753 /*--------------------------------------------------------------------------*/
754 /* set_slave: force evaluation whenever the owner is evaluated.
755 * and: deactivate q_eval...
757 void COMPONENT::set_slave()
759 mark_always_q_for_eval();
760 if (subckt()) {
761 subckt()->set_slave();
762 }else{
765 /*--------------------------------------------------------------------------*/
766 void COMPONENT::set_value(double v, COMMON_COMPONENT* c)
768 if (c != _common) {
769 detach_common();
770 attach_common(c);
771 }else{
773 set_value(v);
775 /*--------------------------------------------------------------------------*/
776 void COMPONENT::set_param_by_name(std::string Name, std::string Value)
778 trace3("COMPONENT::set_param_by_name", Name, has_common(), long_label());
779 if (has_common()) {
780 COMMON_COMPONENT* c = common()->clone();
781 assert(c);
782 c->set_param_by_name(Name, Value);
783 attach_common(c);
784 }else{
785 CARD::set_param_by_name(Name, Value);
788 /*--------------------------------------------------------------------------*/
789 void COMPONENT::set_param_by_index(int i, std::string& Value, int offset)
791 if (has_common()) {untested();
792 COMMON_COMPONENT* c = common()->clone();
793 assert(c);
794 c->set_param_by_index(i, Value, offset);
795 attach_common(c);
796 }else{
797 switch (COMPONENT::param_count() - 1 - i) {
798 case 0: _value = Value; break;
799 case 1: _mfactor = Value; break;
800 default: CARD::set_param_by_index(i, Value, offset);
804 /*--------------------------------------------------------------------------*/
805 bool COMPONENT::param_is_printable(int i)const
807 if (has_common()) {
808 return common()->param_is_printable(i);
809 }else{
810 switch (COMPONENT::param_count() - 1 - i) {
811 case 0: return value().has_hard_value();
812 case 1: return _mfactor.has_hard_value();
813 default:untested(); return CARD::param_is_printable(i);
817 /*--------------------------------------------------------------------------*/
818 std::string COMPONENT::param_name(int i)const
820 if (has_common()) {
821 return common()->param_name(i);
822 }else{
823 switch (COMPONENT::param_count() - 1 - i) {
824 case 0: return value_name();
825 case 1: return "m";
826 default:untested(); return CARD::param_name(i);
830 /*--------------------------------------------------------------------------*/
831 std::string COMPONENT::param_name(int i, int j)const
833 if (has_common()) {untested();
834 return common()->param_name(i,j);
835 }else{
836 if (j == 0) {
837 return param_name(i);
838 }else if (i >= CARD::param_count()) {
839 return "";
840 }else{untested();
841 return CARD::param_name(i,j);
845 /*--------------------------------------------------------------------------*/
846 std::string COMPONENT::param_value(int i)const
848 if (has_common()) {
849 return common()->param_value(i);
850 }else{
851 switch (COMPONENT::param_count() - 1 - i) {
852 case 0: return value().string();
853 case 1: return _mfactor.string();
854 default:untested(); return CARD::param_value(i);
858 /*--------------------------------------------------------------------------*/
859 const std::string COMPONENT::port_value(uint_t i)const
861 assert(_n);
862 assert(i !=INVALID_NODE);
863 assert(i < net_nodes());
864 return _n[i].short_label();
866 /*--------------------------------------------------------------------------*/
867 const std::string COMPONENT::current_port_value(uint_t)const
868 {untested();
869 unreachable();
870 static std::string s;
871 return s;
873 /*--------------------------------------------------------------------------*/
874 const MODEL_CARD* COMPONENT::find_model(const std::string& modelname)const
876 trace2("COMPONENT::find_model", short_label(), modelname);
877 if (modelname == "") {
878 throw Exception(long_label() + ": missing args -- need model name");
879 unreachable();
880 return NULL;
881 }else{
882 const CARD* c = NULL;
884 int bin_count = 0;
885 for (const CARD* Scope = this; Scope && !c; Scope = Scope->owner()) {
886 // start here, looking out
887 try {
888 c = Scope->find_in_my_scope(modelname);
889 trace1("COMPONENT::find_model found model in scope", hp(c));
890 }catch (Exception_Cant_Find& e1) {
891 trace3("COMPONENT::find_model found no model in scope",
892 modelname, Scope->long_label(), hp(Scope->scope()));
893 // didn't find plain model. try binned models
894 bin_count = 0;
895 for (;;) {
896 // loop over binned models
897 std::string extended_name = modelname + '.' + ::to_string(++bin_count);
898 try {
899 c = Scope->find_in_my_scope(extended_name);
900 }catch (Exception_Cant_Find& e2) {
901 // that's all .. looked at all of them
902 c = NULL;
903 break;
905 const MODEL_CARD* m = dynamic_cast<const MODEL_CARD*>(c);
906 if (m && m->is_valid(this)) {
907 //matching name and correct bin
908 break;
909 }else{
910 trace0("COMPONENT::find_model invalid");
911 // keep looking
916 if (!c) {
917 // this does not work!
918 // const MODEL_CARD* m = dynamic_cast<const MODEL_CARD*>(c);
919 // if (m && m->is_valid(this)) { untested();
920 // }else
921 if (bin_count <= 1) {
922 if (model_dispatcher[modelname]) {
923 trace1("COMPONENT::find_model there's a model... ", modelname);
925 trace1("COMPONENT::find_model Exception", modelname);
926 throw Exception_Cant_Find(long_label(), modelname);
927 }else{
928 throw Exception(long_label() + ": no bins match: " + modelname);
930 unreachable();
931 }else{
934 // found something, what is it?
935 assert(c);
936 const MODEL_CARD* model = dynamic_cast<const MODEL_CARD*>(c);
937 if (!model) {
938 trace0("COMPONENT::find_model no model here");
939 throw Exception_Type_Mismatch(long_label(), modelname, ".model");
940 }else if (!model->is_valid(this)) {untested();
941 error(bWARNING, long_label() + ", " + modelname
942 + "\nmodel and device parameters are incompatible, using anyway\n");
944 assert(model);
945 return model;
948 /*--------------------------------------------------------------------------*/
949 double COMPONENT::tr_probe_num(const std::string& x)const
951 CS cmd(CS::_STRING, x);
952 ADP_CARD* a=adp();
953 if (cmd.umatch("v")) {
954 int nn = cmd.ctoi();
955 return (nn > 0 && nn <= int(net_nodes())) ? _n[nn-1].v0() : NOT_VALID;
956 }else if (Umatch(x, "amps |amps0 ")) {
957 return ( 17 );
958 }else if (Umatch(x, "stress ") || Umatch(x, "hci ") ) {
959 return(19);
960 a->tr_probe_num(x);
961 }else if (Umatch(x, "brel ")) {
962 /// std::cout << "rel\n";
963 return ( tr_behaviour_rel );
964 }else if (Umatch(x, "bdel ")) {
965 return ( tr_behaviour_del );
966 }else if (Umatch(x, "sv ")) { // some value (debugging)
967 return ( tr_amps_diff_cur() );
968 }else if (Umatch(x, "next{time} ")) {
969 return (_time_by._error_estimate < BIGBIG) ? _time_by._error_estimate : 0;
970 }else if (Umatch(x, "error{time} ")) { itested();
971 return (_time_by._error_estimate < BIGBIG) ? _time_by._error_estimate-_sim->_time0 : 0;
972 }else if (Umatch(x, "timef{uture} ")) {
973 return (_time_by._error_estimate < _time_by._event)
974 ? _time_by._error_estimate
975 : _time_by._event;
976 }else if (Umatch(x, "te{mperature} ")) {
977 if(has_common())
978 return common()->temp();
979 return _sim->_temp_c;
980 }else if (Umatch(x, "event{time} ")) {
981 return (_time_by._event < BIGBIG) ? _time_by._event : 0;
982 }else if (Umatch(x, "const " )) {
983 return is_constant();
984 }else if (Umatch(x, "conv{erged} ")) {
985 return double( _converged );
986 #ifndef NDEBUG
987 }else if (Umatch(x, "_m ")) {
988 return double(hp( _common->model() ) );
989 }else if (Umatch(x, "_c ")) {
990 return double( hp(_common) );
991 }else if (Umatch(x, "common " )) {
992 return hp(common());
993 #endif
996 return CARD::tr_probe_num(x);
998 /*--------------------------------------------------------------------------*/
999 void COMPONENT::tr_save_amps(int)
1001 return;
1002 #if 0
1003 std::cerr << "COMPONENT::tr_save_amps " << short_label() << "\n";
1004 int j = net_nodes() - 1;
1005 assert(j==1);
1006 j=1;
1007 int k = j;
1008 hp_float_t tramps = 0;//tr_amps();
1009 hp_float_t* trampsp=&tramps;
1011 std::cerr << "saving _amps[ " << n << " ]. have " << net_nodes() << " nodes\n";
1014 if (_amps==0) _tr_amps_diff_cur = 0;
1015 if (_amps==0) _tr_amps_diff_max = 0; // maximum der delta i in diesem zeitschritt.
1017 while (j--> 0){
1018 if(_amps!=0) {
1019 _tr_amps_diff_cur = _amps[n*k + j] - trampsp[j];
1020 _tr_amps_diff_max = fmax( _tr_amps_diff_max, _tr_amps_diff_cur );
1023 std::cerr << short_label() << ": saving _amps[ " << n*k+j << " ]" << _amps << " \n";
1025 hp_float_t tmp=trampsp[j];
1027 std::cerr << " have " << tmp << "\n";
1028 _amps_new[ n*k + j ]= tmp;
1031 trace1("COMPONENT::tr_save_amps" , _tr_amps_diff_max);
1032 tr_behaviour_del = _tr_amps_diff_max;
1033 #endif
1035 /*--------------------------------------------------------------------------*/
1036 void COMPONENT::tt_behaviour_update()
1038 trace1("COMPONENT::tt_behaviour_update" , tr_behaviour_del);
1040 tt_behaviour_del += tr_behaviour_del;
1041 tt_behaviour_rel += tr_behaviour_rel;
1043 //global bahaviour = maximum device bahaviour.
1044 if(tr_behaviour_del > CKT_BASE::tr_behaviour_del)
1046 // std::cerr << "COMPONENT::tr_behaviour " << _sim->_Time0
1047 // << "dev:" << short_label() << " " << tr_behaviour_del << "CKT_BASE: " << CKT_BASE::tr_behaviour_del << "\n";
1050 CKT_BASE::tr_behaviour_del = fmax( CKT_BASE::tr_behaviour_del, tr_behaviour_del);
1051 CKT_BASE::tr_behaviour_rel = fmax( CKT_BASE::tr_behaviour_rel, tr_behaviour_rel);
1052 //std::cerr << "ELEMENT::tr_save_amps: " << short_label() << " " << "del: " << tr_behaviour_del << "rel: " << tr_behaviour_rel << "\n";
1054 assert (tr_behaviour_del >=0 );
1057 /*--------------------------------------------------------------------------*/
1058 /* q_eval: queue this device for evaluation on the next pass,
1059 * with a check against doing it twice.
1061 void COMPONENT::q_eval()
1063 trace1("COMPONENT::q_eval", long_label());
1064 if(!is_q_for_eval()) {
1065 mark_q_for_eval();
1066 _sim->_evalq_uc->push_back(this);
1067 }else{
1070 /*--------------------------------------------------------------------------*/
1071 void COMPONENT::tr_queue_eval()
1073 if(tr_needs_eval()) {
1074 q_eval();
1075 }else{
1078 /*--------------------------------------------------------------------------*/
1079 TIME_PAIR COMPONENT::tr_review()
1081 _time_by.reset();
1082 if(has_common()) {
1083 return _common->tr_review(this);
1084 }else{
1085 return _time_by;
1088 /*--------------------------------------------------------------------------*/
1089 void COMPONENT::tr_accept()
1091 if(has_common()) {
1092 _common->tr_accept(this);
1093 }else{
1096 /*--------------------------------------------------------------------------*/
1097 bool COMPONENT::use_obsolete_callback_parse()const
1099 if (has_common()) {
1100 return common()->use_obsolete_callback_parse();
1101 }else{untested();
1102 return false;
1105 /*--------------------------------------------------------------------------*/
1106 bool COMPONENT::use_obsolete_callback_print()const
1108 if (has_common()) {
1109 return common()->use_obsolete_callback_print();
1110 }else{
1111 return false;
1114 /*--------------------------------------------------------------------------*/
1115 void COMPONENT::obsolete_move_parameters_from_common(const COMMON_COMPONENT* dc)
1117 assert(dc);
1118 _value = dc->value();
1119 _mfactor = dc->mfactor();
1121 /*--------------------------------------------------------------------------*/
1122 /* volts_limited: transient voltage, best approximation, with limiting
1124 double COMPONENT::volts_limited(const node_t & n1, const node_t & n2)
1126 bool limiting = false;
1128 double v1 = n1.v0();
1129 double v2 = n2.v0();
1131 trace3("COMPONENT::volts_limited", v1 ,v2, _sim->_time0);
1132 assert(v1 == v1);
1133 if (v1 < _sim->_vmin) {
1134 limiting = true;
1135 v1 = _sim->_vmin;
1136 }else if (v1 > _sim->_vmax) {
1137 limiting = true;
1138 v1 = _sim->_vmax;
1141 assert(v2 == v2);
1142 if (v2 < _sim->_vmin) {
1143 limiting = true;
1144 v2 = _sim->_vmin;
1145 }else if (v2 > _sim->_vmax) {
1146 limiting = true;
1147 v2 = _sim->_vmax;
1150 if (limiting) {
1151 _sim->_limiting = true;
1152 if (OPT::dampstrategy & dsRANGE) {
1153 _sim->_fulldamp = true;
1154 error(bTRACE, "range limit damp\n");
1156 if (OPT::picky <= bTRACE) { itested();
1157 error(bNOERROR,"node limiting (n1,n2,dif) "
1158 "was (%g %g %g) now (%g %g %g)\n",
1159 n1.v0(), n2.v0(), n1.v0() - n2.v0(), v1, v2, v1-v2);
1163 return dn_diff(v1,v2);
1165 /*--------------------------------------------------------------------------*/
1166 double COMPONENT::tt_probe_num(const std::string& x)const
1168 if (Umatch(x, "bdel ")) {
1169 return ( tt_behaviour_del );
1170 }else if (Umatch(x, "brel ")) {
1171 return ( tt_behaviour_rel );
1174 return tr_probe_num(x);
1177 /*--------------------------------------------------------------------------*/
1178 void COMPONENT::tr_do_behaviour(){
1179 std::cerr << "COMPONENT::tr_do_behaviour() FIXME\n";
1183 /*--------------------------------------------------------------------------*/
1184 void COMPONENT::tt_accept()
1187 // not here...
1188 // double* tmp = _amps;
1189 //_amps = _amps_new;
1190 //_amps_new = tmp;
1192 tt_behaviour_del /= (_sim->_dT0);
1193 tt_behaviour_rel /= (_sim->_dT0);
1195 /*--------------------------------------------------------------------------*/
1196 void COMPONENT::attach_adp(ADP_CARD* a)
1198 if (!a){
1199 return;
1200 } else if(_adp){ untested();
1201 return;
1203 _adp = a;
1204 ADP_LIST::adp_list.push_back( a );
1207 /*--------------------------------------------------------------------------
1209 * need to be careful!
1210 * attach_common will delete a new COMMON if its already there, so better not
1211 * enqueue it here (somethng like that)
1212 COMMON_COMPONENT* COMMON_COMPONENT::deflate()
1214 for( list<const COMMON_COMPONENT*>::iterator i = _commons.begin();
1215 i != _commons.end(); ++i ){
1217 assert(*i);
1218 if (*this == **i){
1219 return const_cast<COMMON_COMPONENT*>( *i );
1222 _commons.push_back(this);
1223 return this;
1225 ------------------------*/
1226 // ELEMENT? not yet.
1227 double COMPONENT::tt_review_check_and_convert(double timestep)
1229 double dT = _sim->_dT0;
1230 double dTmin = _sim->last_time();
1231 double time_future;
1232 if (timestep == NEVER) {
1233 time_future = NEVER;
1234 }else{
1235 double atimestep = timestep;
1236 if (timestep >= dTmin) {
1237 }else{
1238 timestep = dTmin;
1241 if (atimestep < (dT) * OPT::ttreject ) {
1242 error(bTRACE, "tt step rejected: %s\n", long_label().c_str());
1243 error(bTRACE, "new\n");
1244 error(bTRACE, "new=%f required=%f\n", timestep, dT);
1245 time_future = _sim->_Time0 - dT + timestep;
1246 trace3("reject", timestep, dT, time_future);
1247 }else if (timestep - dTmin < dT - dTmin * .5) {
1248 time_future = _sim->_Time0 + timestep;
1249 }else{
1250 time_future = _sim->_Time0 + timestep;
1251 trace3("accept", timestep, dT, time_future);
1254 assert(time_future > 0.);
1255 // assert(time_future > _Time[1]);
1256 return time_future;
1258 /*-------------------------------------------------------------------------------*/
1259 // vim:ts=8:sw=2:noet: