viminfo
[gnucap-felix.git] / lib / e_compon.cc
blob5ae7d983b1814ce820791119bef8d9ac8df1a01c
1 /*$Id: e_compon.cc,v 26.137 2010/04/10 02:37:33 al Exp $ -*- 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 //testing=script,noswitch 2009.07.13
25 #include "u_lang.h"
26 #include "e_model.h"
27 #include "e_elemnt.h"
28 /*--------------------------------------------------------------------------*/
29 COMMON_COMPONENT::COMMON_COMPONENT(const COMMON_COMPONENT& p)
30 :_tnom_c(p._tnom_c),
31 _dtemp(p._dtemp),
32 _temp_c(p._temp_c),
33 _mfactor(p._mfactor),
34 _value(p._value),
35 _modelname(p._modelname),
36 _model(p._model),
37 _attach_count(0)
40 /*--------------------------------------------------------------------------*/
41 COMMON_COMPONENT::COMMON_COMPONENT(int c)
42 :_tnom_c(NOT_INPUT),
43 _dtemp(0),
44 _temp_c(NOT_INPUT),
45 _mfactor(1),
46 _value(0),
47 _modelname(),
48 _model(0),
49 _attach_count(c)
52 /*--------------------------------------------------------------------------*/
53 COMMON_COMPONENT::~COMMON_COMPONENT()
55 trace1("common,destruct", _attach_count);
56 assert(_attach_count == 0 || _attach_count == CC_STATIC);
58 /*--------------------------------------------------------------------------*/
59 void COMMON_COMPONENT::attach_common(COMMON_COMPONENT*c, COMMON_COMPONENT**to)
61 assert(to);
62 if (c == *to) {
63 // The new and old are the same object. Do nothing.
64 }else if (!c) {untested();
65 // There is no new common. probably a simple element
66 detach_common(to);
67 }else if (!*to) {
68 // No old one, but have a new one.
69 ++(c->_attach_count);
70 trace1("++1", c->_attach_count);
71 *to = c;
72 }else if (*c != **to) {
73 // They are different, usually by edit.
74 detach_common(to);
75 ++(c->_attach_count);
76 trace1("++2", c->_attach_count);
77 *to = c;
78 }else if (c->_attach_count == 0) {
79 // The new and old are identical.
80 // Use the old one.
81 // The new one is not used anywhere, so throw it away.
82 trace1("delete", c->_attach_count);
83 delete c;
84 }else{untested();
85 // The new and old are identical.
86 // Use the old one.
87 // The new one is also used somewhere else, so keep it.
90 /*--------------------------------------------------------------------------*/
91 void COMMON_COMPONENT::detach_common(COMMON_COMPONENT** from)
93 assert(from);
94 if (*from) {
95 assert((**from)._attach_count > 0);
96 --((**from)._attach_count);
97 trace1("--", (**from)._attach_count);
98 if ((**from)._attach_count == 0) {
99 trace1("delete", (**from)._attach_count);
100 delete *from;
101 }else{
102 trace1("nodelete", (**from)._attach_count);
104 *from = NULL;
105 }else{
108 /*--------------------------------------------------------------------------*/
109 void COMMON_COMPONENT::attach_model(const COMPONENT* d)const
111 assert(d);
112 _model = d->find_model(modelname());
113 assert(_model);
115 /*--------------------------------------------------------------------------*/
116 void COMMON_COMPONENT::parse_modelname(CS& cmd)
118 set_modelname(cmd.ctos(TOKENTERM));
120 /*--------------------------------------------------------------------------*/
121 // called only by COMMON_COMPONENT::parse_obsolete
122 bool COMMON_COMPONENT::parse_param_list(CS& cmd)
124 unsigned start = cmd.cursor();
125 unsigned here = cmd.cursor();
127 parse_params_obsolete_callback(cmd); //BUG//callback
128 }while (cmd.more() && !cmd.stuck(&here));
129 return cmd.gotit(start);
131 /*--------------------------------------------------------------------------*/
132 void COMMON_COMPONENT::parse_common_obsolete_callback(CS& cmd) //used
134 if (cmd.skip1b('(')) {
135 // start with a paren
136 unsigned start = cmd.cursor();
137 parse_param_list(cmd);
138 if (cmd.gotit(start)) { // ( params ( ....
139 // named args before num list
140 if (cmd.skip1b('(')) { // ( params ( list ) params )
141 parse_numlist(cmd);
142 if (!cmd.skip1b(')')) {untested();
143 cmd.warn(bWARNING, "need )");
144 }else{
146 }else{ // ( params list params )
147 parse_numlist(cmd); //BUG//
149 parse_param_list(cmd);
150 if (!cmd.skip1b(')')) {untested();
151 cmd.warn(bWARNING, "need )");
152 }else{
154 }else{
155 // no named args before num list
156 // but there's a paren
157 // not sure whether it belongs to all args or to num list
158 if (cmd.skip1b('(')) { // ( ( list ) params )
159 // two parens
160 parse_numlist(cmd);
161 if (!cmd.skip1b(')')) {untested();
162 cmd.warn(bWARNING, "need )");
163 }else{
165 parse_param_list(cmd);
166 if (!cmd.skip1b(')')) {untested();
167 cmd.warn(bWARNING, "need )");
168 }else{
170 }else{ // ( list ...
171 // only one paren
172 parse_numlist(cmd);
173 if (cmd.skip1b(')')) { // ( list ) params
174 // assume it belongs to num list
175 // and named params follow
176 parse_param_list(cmd);
177 }else{ // ( list params )
178 // assume it belongs to all args
179 parse_param_list(cmd);
180 if (!cmd.skip1b(')')) {
181 cmd.warn(bWARNING, "need )");
182 }else{
187 }else{
188 // does not start with a paren
189 unsigned start = cmd.cursor();
190 parse_param_list(cmd);
191 if (cmd.gotit(start)) {
192 if (cmd.skip1b('(')) { // params ( list ) params
193 parse_numlist(cmd);
194 if (!cmd.skip1b(')')) {untested();
195 cmd.warn(bWARNING, "need )");
196 }else{
198 }else if (!(cmd.is_alpha())) { // params list params
199 parse_numlist(cmd);
200 }else{ // params (only)
202 }else{ // list params
203 assert(!(cmd.skip1b('(')));
204 parse_numlist(cmd);
206 parse_param_list(cmd);
207 if (cmd.skip1b(')')) {
208 cmd.warn(bWARNING, start, "need (");
209 }else{
213 /*--------------------------------------------------------------------------*/
214 void COMMON_COMPONENT::print_common_obsolete_callback(OMSTREAM& o, LANGUAGE* lang)const
216 assert(lang);
217 print_pair(o, lang, "tnom", _tnom_c, _tnom_c.has_hard_value());
218 print_pair(o, lang, "dtemp",_dtemp, _dtemp.has_hard_value());
219 print_pair(o, lang, "temp", _temp_c, _temp_c.has_hard_value());
220 print_pair(o, lang, "m", _mfactor, _mfactor.has_hard_value());
222 /*--------------------------------------------------------------------------*/
223 void COMMON_COMPONENT::set_param_by_index(int i, std::string& Value, int Offset)
225 switch (i) {
226 case 0: _tnom_c = Value; break;
227 case 1: _dtemp = Value; break;
228 case 2: _temp_c = Value; break;
229 case 3: _mfactor = Value; break;
230 default: throw Exception_Too_Many(i, 3, Offset); break;
233 /*--------------------------------------------------------------------------*/
234 bool COMMON_COMPONENT::param_is_printable(int i)const
236 switch (i) {
237 case 0: return _tnom_c.has_hard_value();
238 case 1: return _dtemp.has_hard_value();
239 case 2: return _temp_c.has_hard_value();
240 case 3: return _mfactor.has_hard_value();
241 default: return false;
244 /*--------------------------------------------------------------------------*/
245 std::string COMMON_COMPONENT::param_name(int i)const
247 switch (i) {
248 case 0: return "tnom";
249 case 1: return "dtemp";
250 case 2: return "temp";
251 case 3: return "m";
252 default: return "";
255 /*--------------------------------------------------------------------------*/
256 std::string COMMON_COMPONENT::param_name(int i, int j)const
258 return (j==0) ? param_name(i) : "";
260 /*--------------------------------------------------------------------------*/
261 std::string COMMON_COMPONENT::param_value(int i)const
263 switch (i) {
264 case 0: return _tnom_c.string();
265 case 1: return _dtemp.string();
266 case 2: return _temp_c.string();
267 case 3: return _mfactor.string();
268 default: return "";
271 /*--------------------------------------------------------------------------*/
272 void COMMON_COMPONENT::precalc_first(const CARD_LIST* Scope)
274 assert(Scope);
275 _tnom_c.e_val(OPT::tnom_c, Scope);
276 _dtemp.e_val(0., Scope);
277 _temp_c.e_val(CKT_BASE::_sim->_temp_c + _dtemp, Scope);
278 _mfactor.e_val(1, Scope);
279 _value.e_val(0, Scope);
281 /*--------------------------------------------------------------------------*/
282 void COMMON_COMPONENT::tr_eval(ELEMENT*x)const
283 {untested();
284 assert(_model);
285 _model->tr_eval(x);
287 /*--------------------------------------------------------------------------*/
288 void COMMON_COMPONENT::ac_eval(ELEMENT*x)const
289 {untested();
290 assert(_model);
291 _model->ac_eval(x);
293 /*--------------------------------------------------------------------------*/
294 bool COMMON_COMPONENT::operator==(const COMMON_COMPONENT& x)const
296 return (_modelname == x._modelname
297 && _model == x._model
298 && _tnom_c == x._tnom_c
299 && _dtemp == x._dtemp
300 && _temp_c == x._temp_c
301 && _mfactor == x._mfactor
302 && _value == x._value);
304 /*--------------------------------------------------------------------------*/
305 void COMMON_COMPONENT::set_param_by_name(std::string Name, std::string Value)
307 if (has_parse_params_obsolete_callback()) {untested();
308 std::string args(Name + "=" + Value);
309 CS cmd(CS::_STRING, args); //obsolete_callback
310 bool ok = parse_params_obsolete_callback(cmd); //BUG//callback
311 if (!ok) {untested();
312 throw Exception_No_Match(Name);
313 }else{untested();
315 }else{
316 //BUG// ugly linear search
317 for (int i = param_count() - 1; i >= 0; --i) {
318 for (int j = 0; param_name(i,j) != ""; ++j) {
319 if (Umatch(Name, param_name(i,j) + ' ')) {
320 set_param_by_index(i, Value, 0/*offset*/);
321 return; //success
322 }else{
323 //keep looking
327 itested();
328 throw Exception_No_Match(Name);
331 /*--------------------------------------------------------------------------*/
332 //BUG// This is a kluge for the spice_wrapper, to disable virtual functions.
333 // It is called during expansion only.
335 void COMMON_COMPONENT::Set_param_by_name(std::string Name, std::string Value)
337 assert(!has_parse_params_obsolete_callback());
339 //BUG// ugly linear search
340 for (int i = COMMON_COMPONENT::param_count() - 1; i >= 0; --i) {
341 for (int j = 0; COMMON_COMPONENT::param_name(i,j) != ""; ++j) {
342 if (Umatch(Name, COMMON_COMPONENT::param_name(i,j) + ' ')) {
343 COMMON_COMPONENT::set_param_by_index(i, Value, 0/*offset*/);
344 return; //success
345 }else{
346 //keep looking
350 throw Exception_No_Match(Name);
352 /*--------------------------------------------------------------------------*/
353 bool COMMON_COMPONENT::parse_numlist(CS&)
355 return false;
357 /*--------------------------------------------------------------------------*/
358 bool COMMON_COMPONENT::parse_params_obsolete_callback(CS& cmd)
360 return ONE_OF
361 || Get(cmd, "tnom", &_tnom_c)
362 || Get(cmd, "dtemp", &_dtemp)
363 || Get(cmd, "temp", &_temp_c)
364 || Get(cmd, "m", &_mfactor)
365 || Get(cmd, "mfactor",&_mfactor)
368 /*--------------------------------------------------------------------------*/
369 /*--------------------------------------------------------------------------*/
370 COMPONENT::COMPONENT()
371 :CARD(),
372 _common(0),
373 _value(0),
374 _mfactor(1),
375 _mfactor_fixed(NOT_VALID),
376 _converged(false),
377 _q_for_eval(-1),
378 _time_by()
380 if (_sim) {
381 _sim->uninit();
382 }else{
385 /*--------------------------------------------------------------------------*/
386 COMPONENT::COMPONENT(const COMPONENT& p)
387 :CARD(p),
388 _common(0),
389 _value(p._value),
390 _mfactor(p._mfactor),
391 _mfactor_fixed(p._mfactor_fixed),
392 _converged(p._converged),
393 _q_for_eval(-1),
394 _time_by(p._time_by)
396 if (_sim) {
397 _sim->uninit();
398 }else{untested();
400 attach_common(p._common);
401 assert(_common == p._common);
403 /*--------------------------------------------------------------------------*/
404 COMPONENT::~COMPONENT()
406 detach_common();
407 if (_sim) {
408 _sim->uninit();
409 }else{
412 /*--------------------------------------------------------------------------*/
413 bool COMPONENT::node_is_grounded(int i)const
415 assert(_n);
416 assert(i >= 0);
417 assert(i < net_nodes());
418 return _n[i].is_grounded();
420 /*--------------------------------------------------------------------------*/
421 bool COMPONENT::node_is_connected(int i)const
423 assert(_n);
424 assert(i >= 0);
425 assert(i < net_nodes());
426 return _n[i].is_connected();
428 /*--------------------------------------------------------------------------*/
429 void COMPONENT::set_port_by_name(std::string& int_name, std::string& ext_name)
430 {itested();
431 for (int i=0; i<max_nodes(); ++i) {itested();
432 if (int_name == port_name(i)) {itested();
433 set_port_by_index(i, ext_name);
434 return;
435 }else{itested();
438 untested();
439 throw Exception_No_Match(int_name);
441 /*--------------------------------------------------------------------------*/
442 void COMPONENT::set_port_by_index(int num, std::string& ext_name)
444 if (num <= max_nodes()) {
445 _n[num].new_node(ext_name, this);
446 if (num+1 > _net_nodes) {
447 // make the list bigger
448 _net_nodes = num+1;
449 }else{itested();
450 // it's already big enough, probably assigning out of order
452 }else{untested();
453 throw Exception_Too_Many(num, max_nodes(), 0/*offset*/);
456 /*--------------------------------------------------------------------------*/
457 void COMPONENT::set_port_to_ground(int num)
458 {untested();
459 if (num <= max_nodes()) {untested();
460 _n[num].set_to_ground(this);
461 if (num+1 > _net_nodes) {untested();
462 _net_nodes = num+1;
463 }else{untested();
465 }else{untested();
466 throw Exception_Too_Many(num, max_nodes(), 0/*offset*/);
469 /*--------------------------------------------------------------------------*/
470 void COMPONENT::set_dev_type(const std::string& new_type)
472 if (common()) {
473 if (new_type != dev_type()) {
474 COMMON_COMPONENT* c = common()->clone();
475 assert(c);
476 c->set_modelname(new_type);
477 attach_common(c);
478 }else{
480 }else{
481 CARD::set_dev_type(new_type);
484 /*--------------------------------------------------------------------------*/
485 void COMPONENT::print_args_obsolete_callback(OMSTREAM& o, LANGUAGE* lang)const
487 assert(lang);
488 assert(has_common());
489 common()->print_common_obsolete_callback(o, lang);
491 /*--------------------------------------------------------------------------*/
492 void COMPONENT::deflate_common()
493 {untested();
494 unreachable();
495 if (has_common()) {untested();
496 COMMON_COMPONENT* deflated_common = mutable_common()->deflate();
497 if (deflated_common != common()) {untested();
498 attach_common(deflated_common);
499 }else{untested();
501 }else{untested();
502 unreachable();
505 /*--------------------------------------------------------------------------*/
506 void COMPONENT::expand()
508 CARD::expand();
509 if (has_common()) {
510 COMMON_COMPONENT* new_common = common()->clone();
511 new_common->expand(this);
512 COMMON_COMPONENT* deflated_common = new_common->deflate();
513 if (deflated_common != common()) {
514 attach_common(deflated_common);
515 }else{untested();
517 }else{
520 /*--------------------------------------------------------------------------*/
521 void COMPONENT::precalc_first()
523 CARD::precalc_first();
524 if (has_common()) {
525 try {
526 mutable_common()->precalc_first(scope());
527 }catch (Exception_Precalc& e) {
528 error(bWARNING, long_label() + ": " + e.message());
530 _mfactor = common()->mfactor();
531 }else{
534 _mfactor.e_val(1, scope());
535 _value.e_val(0.,scope());
536 trace1(long_label().c_str(), double(_mfactor));
537 if (const COMPONENT* o = prechecked_cast<const COMPONENT*>(owner())) {
538 _mfactor_fixed = o->mfactor() * _mfactor;
539 }else{
540 _mfactor_fixed = _mfactor;
542 trace1(long_label().c_str(), _mfactor_fixed);
544 /*--------------------------------------------------------------------------*/
545 void COMPONENT::precalc_last()
547 CARD::precalc_last();
548 if (has_common()) {
549 try {
550 mutable_common()->precalc_last(scope());
551 }catch (Exception_Precalc& e) {
552 error(bWARNING, long_label() + ": " + e.message());
554 }else{
557 /*--------------------------------------------------------------------------*/
558 void COMPONENT::map_nodes()
560 assert(is_device());
561 assert(0 <= min_nodes());
562 //assert(min_nodes() <= net_nodes());
563 assert(net_nodes() <= max_nodes());
564 //assert(ext_nodes() + int_nodes() == matrix_nodes());
566 for (int ii = 0; ii < ext_nodes()+int_nodes(); ++ii) {
567 _n[ii].map();
570 if (subckt()) {
571 subckt()->map_nodes();
572 }else{
575 /*--------------------------------------------------------------------------*/
576 void COMPONENT::tr_iwant_matrix()
578 if (is_device()) {
579 assert(matrix_nodes() == 0);
580 if (subckt()) {
581 subckt()->tr_iwant_matrix();
582 }else{untested();
584 }else{
587 /*--------------------------------------------------------------------------*/
588 void COMPONENT::ac_iwant_matrix()
590 if (is_device()) {
591 assert(matrix_nodes() == 0);
592 if (subckt()) {
593 subckt()->ac_iwant_matrix();
594 }else{untested();
596 }else{
599 /*--------------------------------------------------------------------------*/
600 /* set: set parameters, used in model building
602 void COMPONENT::set_parameters(const std::string& Label, CARD *Owner,
603 COMMON_COMPONENT *Common, double Value,
604 int , double [],
605 int node_count, const node_t Nodes[])
607 set_label(Label);
608 set_owner(Owner);
609 set_value(Value);
610 attach_common(Common);
612 assert(node_count <= net_nodes());
613 notstd::copy_n(Nodes, node_count, _n);
615 /*--------------------------------------------------------------------------*/
616 /* set_slave: force evaluation whenever the owner is evaluated.
618 void COMPONENT::set_slave()
620 mark_always_q_for_eval();
621 if (subckt()) {
622 subckt()->set_slave();
623 }else{
626 /*--------------------------------------------------------------------------*/
627 void COMPONENT::set_value(double v, COMMON_COMPONENT* c)
629 if (c != _common) {
630 detach_common();
631 attach_common(c);
632 }else{
634 set_value(v);
636 /*--------------------------------------------------------------------------*/
637 void COMPONENT::set_param_by_name(std::string Name, std::string Value)
639 if (has_common()) {
640 COMMON_COMPONENT* c = common()->clone();
641 assert(c);
642 c->set_param_by_name(Name, Value);
643 attach_common(c);
644 }else{
645 CARD::set_param_by_name(Name, Value);
648 /*--------------------------------------------------------------------------*/
649 void COMPONENT::set_param_by_index(int i, std::string& Value, int offset)
651 if (has_common()) {untested();
652 COMMON_COMPONENT* c = common()->clone();
653 assert(c);
654 c->set_param_by_index(i, Value, offset);
655 attach_common(c);
656 }else{
657 switch (COMPONENT::param_count() - 1 - i) {
658 case 0: _value = Value; break;
659 case 1: _mfactor = Value; break;
660 default: CARD::set_param_by_index(i, Value, offset);
664 /*--------------------------------------------------------------------------*/
665 bool COMPONENT::param_is_printable(int i)const
667 if (has_common()) {
668 return common()->param_is_printable(i);
669 }else{
670 switch (COMPONENT::param_count() - 1 - i) {
671 case 0: return value().has_hard_value();
672 case 1: return _mfactor.has_hard_value();
673 default: return CARD::param_is_printable(i);
677 /*--------------------------------------------------------------------------*/
678 std::string COMPONENT::param_name(int i)const
680 if (has_common()) {
681 return common()->param_name(i);
682 }else{
683 switch (COMPONENT::param_count() - 1 - i) {
684 case 0: return value_name();
685 case 1: return "m";
686 default: return CARD::param_name(i);
690 /*--------------------------------------------------------------------------*/
691 std::string COMPONENT::param_name(int i, int j)const
693 if (has_common()) {untested();
694 return common()->param_name(i,j);
695 }else{
696 if (j == 0) {
697 return param_name(i);
698 }else if (i >= CARD::param_count()) {untested();
699 return "";
700 }else{untested();
701 return CARD::param_name(i,j);
705 /*--------------------------------------------------------------------------*/
706 std::string COMPONENT::param_value(int i)const
708 if (has_common()) {
709 return common()->param_value(i);
710 }else{
711 switch (COMPONENT::param_count() - 1 - i) {
712 case 0: return value().string();
713 case 1: return _mfactor.string();
714 default: return CARD::param_value(i);
718 /*--------------------------------------------------------------------------*/
719 const std::string COMPONENT::port_value(int i)const
721 assert(_n);
722 assert(i >= 0);
723 assert(i < net_nodes());
724 return _n[i].short_label();
726 /*--------------------------------------------------------------------------*/
727 const std::string COMPONENT::current_port_value(int)const
728 {untested();
729 unreachable();
730 static std::string s;
731 return s;
733 /*--------------------------------------------------------------------------*/
734 double COMPONENT::tr_probe_num(const std::string& x)const
736 CS cmd(CS::_STRING, x);
737 if (cmd.umatch("v")) {
738 int nn = cmd.ctoi();
739 return (nn > 0 && nn <= net_nodes()) ? _n[nn-1].v0() : NOT_VALID;
740 }else if (Umatch(x, "error{time} |next{time} ")) {
741 return (_time_by._error_estimate < BIGBIG) ? _time_by._error_estimate : 0;
742 }else if (Umatch(x, "timef{uture} ")) {
743 return (_time_by._error_estimate < _time_by._event)
744 ? _time_by._error_estimate
745 : _time_by._event;
746 }else if (Umatch(x, "event{time} ")) {
747 return (_time_by._event < BIGBIG) ? _time_by._event : 0;
748 }else{
749 return CARD::tr_probe_num(x);
752 /*--------------------------------------------------------------------------*/
753 const MODEL_CARD* COMPONENT::find_model(const std::string& modelname)const
755 if (modelname == "") {
756 throw Exception(long_label() + ": missing args -- need model name");
757 unreachable();
758 return NULL;
759 }else{
760 const CARD* c = NULL;
762 int bin_count = 0;
763 for (const CARD* Scope = this; Scope && !c; Scope = Scope->owner()) {
764 // start here, looking out
765 try {
766 c = Scope->find_in_my_scope(modelname);
767 }catch (Exception_Cant_Find& e1) {
768 // didn't find plain model. try binned models
769 bin_count = 0;
770 for (;;) {
771 // loop over binned models
772 std::string extended_name = modelname + '.' + to_string(++bin_count);
773 try {
774 c = Scope->find_in_my_scope(extended_name);
775 }catch (Exception_Cant_Find& e2) {
776 // that's all .. looked at all of them
777 c = NULL;
778 break;
780 const MODEL_CARD* m = dynamic_cast<const MODEL_CARD*>(c);
781 if (m && m->is_valid(this)) {
782 //matching name and correct bin
783 break;
784 }else{
785 // keep looking
790 if (!c) {
791 if (bin_count <= 1) {
792 throw Exception_Cant_Find(long_label(), modelname);
793 }else{
794 throw Exception(long_label() + ": no bins match: " + modelname);
796 unreachable();
797 }else{
800 // found something, what is it?
801 assert(c);
802 const MODEL_CARD* model = dynamic_cast<const MODEL_CARD*>(c);
803 if (!model) {untested();
804 throw Exception_Type_Mismatch(long_label(), modelname, ".model");
805 }else if (!model->is_valid(this)) {itested();
806 error(bWARNING, long_label() + ", " + modelname
807 + "\nmodel and device parameters are incompatible, using anyway\n");
808 }else{
810 assert(model);
811 return model;
814 /*--------------------------------------------------------------------------*/
815 /* q_eval: queue this device for evaluation on the next pass,
816 * with a check against doing it twice.
818 void COMPONENT::q_eval()
820 if(!is_q_for_eval()) {
821 mark_q_for_eval();
822 _sim->_evalq_uc->push_back(this);
823 }else{itested();
826 /*--------------------------------------------------------------------------*/
827 void COMPONENT::tr_queue_eval()
829 if(tr_needs_eval()) {
830 q_eval();
831 }else{
834 /*--------------------------------------------------------------------------*/
835 TIME_PAIR COMPONENT::tr_review()
837 _time_by.reset();
838 if(has_common()) {
839 return _common->tr_review(this);
840 }else{
841 return _time_by;
844 /*--------------------------------------------------------------------------*/
845 void COMPONENT::tr_accept()
847 if(has_common()) {
848 _common->tr_accept(this);
849 }else{
852 /*--------------------------------------------------------------------------*/
853 bool COMPONENT::use_obsolete_callback_parse()const
855 if (has_common()) {
856 return common()->use_obsolete_callback_parse();
857 }else{
858 return false;
861 /*--------------------------------------------------------------------------*/
862 bool COMPONENT::use_obsolete_callback_print()const
864 if (has_common()) {
865 return common()->use_obsolete_callback_print();
866 }else{
867 return false;
870 /*--------------------------------------------------------------------------*/
871 void COMPONENT::obsolete_move_parameters_from_common(const COMMON_COMPONENT* dc)
873 assert(dc);
874 _value = dc->value();
875 _mfactor = dc->mfactor();
877 /*--------------------------------------------------------------------------*/
878 /* volts_limited: transient voltage, best approximation, with limiting
880 double COMPONENT::volts_limited(const node_t & n1, const node_t & n2)
882 bool limiting = false;
884 double v1 = n1.v0();
885 assert(v1 == v1);
886 if (v1 < _sim->_vmin) {
887 limiting = true;
888 v1 = _sim->_vmin;
889 }else if (v1 > _sim->_vmax) {
890 limiting = true;
891 v1 = _sim->_vmax;
894 double v2 = n2.v0();
895 assert(v2 == v2);
896 if (v2 < _sim->_vmin) {
897 limiting = true;
898 v2 = _sim->_vmin;
899 }else if (v2 > _sim->_vmax) {
900 limiting = true;
901 v2 = _sim->_vmax;
904 if (limiting) {
905 _sim->_limiting = true;
906 if (OPT::dampstrategy & dsRANGE) {
907 _sim->_fulldamp = true;
908 error(bTRACE, "range limit damp\n");
910 if (OPT::picky <= bTRACE) {untested();
911 error(bNOERROR,"node limiting (n1,n2,dif) "
912 "was (%g %g %g) now (%g %g %g)\n",
913 n1.v0(), n2.v0(), n1.v0() - n2.v0(), v1, v2, v1-v2);
917 return dn_diff(v1,v2);
919 /*--------------------------------------------------------------------------*/
920 /*--------------------------------------------------------------------------*/
921 // vim:ts=8:sw=2:noet: