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)
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
21 *------------------------------------------------------------------
22 * Base class for elements of a circuit
33 /*--------------------------------------------------------------------------*/
34 using notstd::to_lower
;
36 /*--------------------------------------------------------------------------*/
37 using notstd::to_lower
;
39 /*--------------------------------------------------------------------------*/
40 COMMON_COMPONENT::COMMON_COMPONENT(const COMMON_COMPONENT
& p
)
47 _modelname(p
._modelname
),
51 trace1(("COMMON_COMPONENT copy, modelname: "+p
._modelname
), hp(_model
) );
53 /*--------------------------------------------------------------------------*/
54 COMMON_COMPONENT::COMMON_COMPONENT(int 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
)
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
85 // No old one, but have a new one.
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
);
96 }else if (c
->_attach_count
== 0) {
97 // The new and old are identical.
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
));
103 trace0("COMMON_COMPONENT::attach_common same twice");
105 // The new and old are identical.
107 // The new one is also used somewhere else, so keep it.
110 /*--------------------------------------------------------------------------*/
111 void COMMON_COMPONENT::detach_common(COMMON_COMPONENT
** from
)
115 assert((**from
)._attach_count
> 0);
116 //assert((**from)._attach_count != CC_STATIC );
117 --((**from
)._attach_count
);
118 if ((**from
)._attach_count
== 0) {
126 /*--------------------------------------------------------------------------*/
127 void COMMON_COMPONENT::attach_model(const COMPONENT
* d
)const
130 trace1("COMMON_COMPONENT::attach_model to", d
->short_label());
132 _model
= d
->find_model(modelname());
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 )
166 if (!cmd
.skip1b(')')) {untested();
167 cmd
.warn(bWARNING
, "need )");
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 )");
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 )
185 if (!cmd
.skip1b(')')) {untested();
186 cmd
.warn(bWARNING
, "need )");
189 parse_param_list(cmd
);
190 if (!cmd
.skip1b(')')) {untested();
191 cmd
.warn(bWARNING
, "need )");
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 )");
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
218 if (!cmd
.skip1b(')')) {untested();
219 cmd
.warn(bWARNING
, "need )");
222 }else if (!(cmd
.is_alpha())) { // params list params
224 }else{ // params (only)
226 }else{ // list params
227 assert(!(cmd
.skip1b('(')));
230 parse_param_list(cmd
);
231 if (cmd
.skip1b(')')) {
232 cmd
.warn(bWARNING
, start
, "need (");
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());
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
)
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;
256 throw Exception_Too_Many(unsigned(i
), 3u, Offset
); break;
259 /*--------------------------------------------------------------------------*/
260 bool COMMON_COMPONENT::param_is_printable(int i
)const
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
274 case 0:itested(); return "tnom";
275 case 1:itested(); return "dtemp";
276 case 2:itested(); return "temp";
278 default:untested(); return "";
281 /*--------------------------------------------------------------------------*/
282 std::string
COMMON_COMPONENT::param_name(int i
, int j
)const
284 return (j
==0) ? param_name(i
) : "";
286 /*--------------------------------------------------------------------------*/
287 std::string
COMMON_COMPONENT::param_value(int i
)const
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
)
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
311 _model
->do_tt_commit(x
);
313 /*--------------------------------------------------------------------------*/
314 void COMMON_COMPONENT::tr_eval(ELEMENT
*x
)const
318 //printf("typeid(_model): %s", typeid(_model).name());
322 /*--------------------------------------------------------------------------*/
323 void COMMON_COMPONENT::ac_eval(ELEMENT
*x
)const
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
]);
352 PARA_BASE
* p
= &(this->*x
);
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
);
366 }else if (Umatch(Name
, "tnom")) { untested();
368 }else if (Umatch(Name
, "dtemp")) { untested();
370 }else if (Umatch(Name
, "temp")) { untested();
372 }else if (Umatch(Name
, "m")) {
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
<< ": ";
381 set_param_by_index(i
, Value
, 0/*offset*/);
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
)
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*/);
410 throw Exception_No_Match(Name
);
412 /*--------------------------------------------------------------------------*/
413 bool COMMON_COMPONENT::parse_numlist(CS
&)
417 /*--------------------------------------------------------------------------*/
418 bool COMMON_COMPONENT::parse_params_obsolete_callback(CS
& cmd
)
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()
435 _mfactor_fixed(NOT_VALID
),
442 trace1("COMPONENT::COMPONENT", long_label());
448 /*--------------------------------------------------------------------------*/
449 COMPONENT::COMPONENT(const COMPONENT
& p
)
453 _mfactor(p
._mfactor
),
454 _mfactor_fixed(p
._mfactor_fixed
),
455 _converged(p
._converged
),
457 _time_by(p
._time_by
),
465 trace0("attaching common");
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
);
482 /*--------------------------------------------------------------------------*/
483 bool COMPONENT::node_is_grounded(uint_t i
)const
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
494 assert(i
!= INVALID_NODE
);
495 if (i
>= net_nodes()) {
496 trace3( "COMPONENT::node_is_connected", i
, net_nodes(), _net_nodes
);
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
);
511 throw Exception_No_Match(int_name
);
513 /*--------------------------------------------------------------------------*/
515 #include "e_cardlist.h"
517 #include "u_nodemap.h"
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() );
530 inline void trace_nodenames(const CARD_LIST
*){}
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
542 // it's already big enough, probably assigning out of order
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
) {
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
);
567 if (new_type
!= dev_type()) {
568 COMMON_COMPONENT
* c
= common()->clone();
570 c
->set_modelname(new_type
);
575 CARD::set_dev_type(new_type
);
578 /*--------------------------------------------------------------------------*/
579 void COMPONENT::print_args_obsolete_callback(OMSTREAM
& o
, LANGUAGE
* lang
)const
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();
590 /*--------------------------------------------------------------------------*/
591 void COMPONENT::deflate_common()
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
);
605 /*--------------------------------------------------------------------------*/
606 void COMPONENT::expand()
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
) {
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();
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();
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
;
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();
657 trace1("COMPONENT::precalc_last", long_label());
659 mutable_common()->precalc_last(scope());
660 }catch (Exception_Precalc
& e
) {
661 error(bWARNING
, long_label() + ": " + e
.message());
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();
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() );
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;
697 subckt()->map_nodes();
701 /*--------------------------------------------------------------------------*/
702 void COMPONENT::tr_iwant_matrix()
705 assert(matrix_nodes() == 0);
707 subckt()->tr_iwant_matrix();
708 }else{ // untested();
713 /*--------------------------------------------------------------------------*/
714 void COMPONENT::ac_iwant_matrix()
717 assert(matrix_nodes() == 0);
719 subckt()->ac_iwant_matrix();
720 }else{ // untested();
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());
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();
761 subckt()->set_slave();
765 /*--------------------------------------------------------------------------*/
766 void COMPONENT::set_value(double v
, COMMON_COMPONENT
* c
)
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());
780 COMMON_COMPONENT
* c
= common()->clone();
782 c
->set_param_by_name(Name
, Value
);
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();
794 c
->set_param_by_index(i
, Value
, offset
);
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
808 return common()->param_is_printable(i
);
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
821 return common()->param_name(i
);
823 switch (COMPONENT::param_count() - 1 - i
) {
824 case 0: return value_name();
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
);
837 return param_name(i
);
838 }else if (i
>= CARD::param_count()) {
841 return CARD::param_name(i
,j
);
845 /*--------------------------------------------------------------------------*/
846 std::string
COMPONENT::param_value(int i
)const
849 return common()->param_value(i
);
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
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
870 static std::string 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");
882 const CARD
* c
= NULL
;
885 for (const CARD
* Scope
= this; Scope
&& !c
; Scope
= Scope
->owner()) {
886 // start here, looking out
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
896 // loop over binned models
897 std::string extended_name
= modelname
+ '.' + ::to_string(++bin_count
);
899 c
= Scope
->find_in_my_scope(extended_name
);
900 }catch (Exception_Cant_Find
& e2
) {
901 // that's all .. looked at all of them
905 const MODEL_CARD
* m
= dynamic_cast<const MODEL_CARD
*>(c
);
906 if (m
&& m
->is_valid(this)) {
907 //matching name and correct bin
910 trace0("COMPONENT::find_model invalid");
917 // this does not work!
918 // const MODEL_CARD* m = dynamic_cast<const MODEL_CARD*>(c);
919 // if (m && m->is_valid(this)) { untested();
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
);
928 throw Exception(long_label() + ": no bins match: " + modelname
);
934 // found something, what is it?
936 const MODEL_CARD
* model
= dynamic_cast<const MODEL_CARD
*>(c
);
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");
948 /*--------------------------------------------------------------------------*/
949 double COMPONENT::tr_probe_num(const std::string
& x
)const
951 CS
cmd(CS::_STRING
, x
);
953 if (cmd
.umatch("v")) {
955 return (nn
> 0 && nn
<= int(net_nodes())) ? _n
[nn
-1].v0() : NOT_VALID
;
956 }else if (Umatch(x
, "amps |amps0 ")) {
958 }else if (Umatch(x
, "stress ") || Umatch(x
, "hci ") ) {
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
976 }else if (Umatch(x
, "te{mperature} ")) {
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
);
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 " )) {
996 return CARD::tr_probe_num(x
);
998 /*--------------------------------------------------------------------------*/
999 void COMPONENT::tr_save_amps(int)
1003 std::cerr
<< "COMPONENT::tr_save_amps " << short_label() << "\n";
1004 int j
= net_nodes() - 1;
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.
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
;
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()) {
1066 _sim
->_evalq_uc
->push_back(this);
1070 /*--------------------------------------------------------------------------*/
1071 void COMPONENT::tr_queue_eval()
1073 if(tr_needs_eval()) {
1078 /*--------------------------------------------------------------------------*/
1079 TIME_PAIR
COMPONENT::tr_review()
1083 return _common
->tr_review(this);
1088 /*--------------------------------------------------------------------------*/
1089 void COMPONENT::tr_accept()
1092 _common
->tr_accept(this);
1096 /*--------------------------------------------------------------------------*/
1097 bool COMPONENT::use_obsolete_callback_parse()const
1100 return common()->use_obsolete_callback_parse();
1105 /*--------------------------------------------------------------------------*/
1106 bool COMPONENT::use_obsolete_callback_print()const
1109 return common()->use_obsolete_callback_print();
1114 /*--------------------------------------------------------------------------*/
1115 void COMPONENT::obsolete_move_parameters_from_common(const COMMON_COMPONENT
* 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
);
1133 if (v1
< _sim
->_vmin
) {
1136 }else if (v1
> _sim
->_vmax
) {
1142 if (v2
< _sim
->_vmin
) {
1145 }else if (v2
> _sim
->_vmax
) {
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()
1188 // double* tmp = _amps;
1189 //_amps = _amps_new;
1192 tt_behaviour_del
/= (_sim
->_dT0
);
1193 tt_behaviour_rel
/= (_sim
->_dT0
);
1195 /*--------------------------------------------------------------------------*/
1196 void COMPONENT::attach_adp(ADP_CARD
* a
)
1200 } else if(_adp
){ untested();
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 ){
1219 return const_cast<COMMON_COMPONENT*>( *i );
1222 _commons.push_back(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();
1232 if (timestep
== NEVER
) {
1233 time_future
= NEVER
;
1235 double atimestep
= timestep
;
1236 if (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
;
1250 time_future
= _sim
->_Time0
+ timestep
;
1251 trace3("accept", timestep
, dT
, time_future
);
1254 assert(time_future
> 0.);
1255 // assert(time_future > _Time[1]);
1258 /*-------------------------------------------------------------------------------*/
1259 // vim:ts=8:sw=2:noet: