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
24 #include "m_divdiff.h"
28 /*--------------------------------------------------------------------------*/
44 assert(_y
[0].x
== 0. && _y
[0].f0
== 0. && _y
[0].f1
== 0.);
47 std::fill_n(_time
, int(OPT::_keep_time_steps
), 0.);
49 /*--------------------------------------------------------------------------*/
50 ELEMENT::ELEMENT(const ELEMENT
& p
)
52 _input_order(p
._input_order
),
64 trace0(long_label().c_str());
66 if (p
._n
== p
._nodes
) {
67 for (int ii
= 0; ii
< NODES_PER_BRANCH
; ++ii
) {
72 // the constructor for a derived class will take care of it
74 assert(_y
[0].x
== 0. && _y
[0].f0
== 0. && _y
[0].f1
== 0.);
77 notstd::copy_n(p
._time
, int(OPT::_keep_time_steps
), _time
);
79 /*--------------------------------------------------------------------------*/
80 bool ELEMENT::skip_dev_type(CS
& cmd
)
82 return cmd
.umatch(dev_type() + ' ');
84 /*--------------------------------------------------------------------------*/
85 void ELEMENT::expand()
87 trace3("ELEMENT::expand", long_label(), input_order(), hp(common()));
88 assert(!subckt() || subckt()->size() < 2);
93 if (!subckt()) new_subckt();
94 trace3("DEV_VCVS::expand branch", long_label(), hp(common()), input_order());
95 ELEMENT
* more
= prechecked_cast
<ELEMENT
*>(clone());
96 node_t nodes
[input_order()*2];
99 notstd::copy_n(_n
+4, input_order()*2-2, nodes
+2);
100 assert(mutable_common()==common());
101 more
->set_parameters("branch", this, mutable_common(), 0., 0, NULL
, input_order()*2, nodes
);
102 more
->set_input_order(input_order()-1);
103 subckt()->push_front(more
);
104 subckt()->set_slave();
106 assert(more
->common() == common());
108 trace2("DEV_VCVS::expand branch", hp(more
->common()), hp(common()));
109 assert(more
->common() == common());
113 if (input_order()>1) {
114 if (!subckt()) new_subckt();
115 trace3("ELEMENT::expand branch", long_label(), hp(common()), input_order());
116 ELEMENT
* more
= prechecked_cast
<ELEMENT
*>(clone());
117 node_t
* nodes
= new node_t
[input_order()*2];
120 notstd::copy_n(_n
+4, input_order()*2-2, nodes
+2);
122 assert(mutable_common()==common());
123 more
->set_input_order(input_order()-1);
124 more
->set_parameters("branch", this, mutable_common(), 0., 0, NULL
, 2+(input_order()-1)*ports_per_input(), nodes
);
126 for (unsigned i
=1; i
<num_current_ports(); i
++) {
127 string a
= current_port_value(i
);
128 more
->set_port_by_index(i
+1, a
);
131 // for(unsigned i=4; i<net_nodes(); i++){untested();
132 // string a = port_value(i);
133 // trace2("ELEMENT::expand ", i, a);
134 // more->set_port_by_index(i-2, a);
137 subckt()->push_front(more
);
138 subckt()->set_slave();
140 assert(more
->common() == common());
141 trace2("DEV_CCSRC::expand branch", hp(more
->common()), hp(common()));
143 // assert(more->common() == common()); maybe not.
148 /*--------------------------------------------------------------------------*/
149 void ELEMENT::precalc_last()
151 COMPONENT::precalc_last();
153 //BUG// This is needed for AC analysis without doing op (or dc or tran ...) first.
154 // Something like it should be moved to ac_begin.
155 if (_sim
->has_op() == s_NONE
) {
162 /*--------------------------------------------------------------------------*/
163 void ELEMENT::tr_begin()
166 trace4("ELEMENT::tr_begin", long_label(), value(), has_common(), tr_needs_eval());
167 if (_sim
->_time0
) { untested();
169 _time
[0] = _sim
->_time0
;
174 for (int i
=1; i
<OPT::_keep_time_steps
; ++i
) {
175 _time
[i
] = _sim
->_time0
;
176 _y
[i
] = FPOLY1(0., 0., 0.);
180 /*--------------------------------------------------------------------------*/
181 void ELEMENT::tr_restore()
183 if (_time
[0] > _sim
->_time0
) {
186 //BUG// wrong values in _time[]
187 for (int i
=0 ; i
<OPT::_keep_time_steps
-1; ++i
) {
188 _time
[i
] = _time
[i
+1];
191 _time
[OPT::_keep_time_steps
-1] = 0.;
192 _y
[OPT::_keep_time_steps
-1] = FPOLY1(0., 0., 0.);
193 }else if (_time
[0] == _sim
->_time0
) {
194 // the usual continue where the last one left off
196 // skipping ahead, not implemented
199 //assert(_time[0] == _sim->_time0);
202 }else if (_time
[0] != _sim
->_time0
) {
203 error(bDANGER
, "//BUG// %s restore time mismatch. t0=%.12f, s->t=%.12f\n", long_label().c_str(),
204 _time
[0], _sim
->_time0
);
207 for (int i
=OPT::_keep_time_steps
-1; i
>=0; --i
) {
208 _time
[i
] = _sim
->_time0
;
210 for (int i
=1 ; i
<OPT::_keep_time_steps
-1; ++i
) {
213 //BUG// happens when continuing after a ^c,
214 // when the last step was not printed
215 //BUG// also happens with _freezetime
216 // _time[0] is the non-printed time. _sim->_time0 is the printed time.
220 for (int i
=OPT::_keep_time_steps
-1; i
>0; --i
) {
221 assert(_time
[i
] < _time
[i
-1] || _time
[i
] == 0. || _time
[i
] == _sim
->_time0
);
224 /*--------------------------------------------------------------------------*/
225 void ELEMENT::dc_advance()
227 assert(_sim
->_time0
== 0.); // DC
229 for (int i
=OPT::_keep_time_steps
-1; i
>=0; --i
) {
230 if(_time
[i
] == _sim
->_time0
){
232 // in _dc_cont case allow to skip dc analysis....
233 _time
[i
] = _sim
->_time0
;
239 /*--------------------------------------------------------------------------*/
240 void ELEMENT::tr_advance()
242 assert(_time
[0] < _sim
->_time0
); // moving forward
244 for (int i
=OPT::_keep_time_steps
-1; i
>0; --i
) {
245 assert(_time
[i
] < _time
[i
-1] || _time
[i
] == 0. || _time
[i
] < _sim
->_time0
);
246 _time
[i
] = _time
[i
-1];
249 _time
[0] = _sim
->_time0
;
251 _dt
= _time
[0] - _time
[1];
254 for (unsigned i
=0;i
< net_nodes(); ++i
) {
255 d
|= _n
[i
]->discont();
256 assert(_n
[i
].n_() != &ground_node
|| !_n
[i
]->discont());
263 }else if (_trsteporder
< (int)OPT::trsteporder
) {
267 /*--------------------------------------------------------------------------*/
268 void ELEMENT::tr_regress()
270 trace4("ELEMENT::tr_regress", long_label(), _sim
->_time0
, _time
[0], _time
[1]);
271 assert(is_constant() || _time
[0] >= _sim
->_time0
); // moving backwards
272 assert(_time
[1] <= _sim
->_time0
); // but not too far backwards
274 for (int i
=OPT::_keep_time_steps
-1; i
>0; --i
) {
276 assert(_time
[i
] < _time
[i
-1] || _time
[i
] == 0. || _time
[i
] == _sim
->_time0
);
278 _time
[0] = _sim
->_time0
;
280 _dt
= _time
[0] - _time
[1];
282 /*--------------------------------------------------------------------------*/
283 /*--------------------------------------------------------------------------*/
284 /* some regress hack??
285 void ELEMENT::tr_regress()
287 trace3("ELEMENT::tr_regress", _time[0], _time[1], _sim->_time0);
288 assert(_time[0] >= _sim->_time0); // moving backwards
289 // assert(_time[1] <= _sim->_time0); // but not too far backwards
290 if ( _time[1] < _sim->_time0){
291 error(bDANGER, "regress %s //BUG// some time mismatch. _time[1]=%.17f, _sim->_time0=%.17f\n",
292 (short_label()).c_str(),
293 _time[1], _sim->_time0);
296 for (int i=OPT::_keep_time_steps-1; i>0; --i) {
297 assert(_time[i] < _time[i-1] || _time[i] == 0.);
299 _time[0] = _sim->_time0;
301 _dt = _time[0] - _time[1];
304 /*--------------------------------------------------------------------------*/
305 TIME_PAIR
ELEMENT::tr_review()
307 trace2("ELEMENT::tr_review", long_label(), order());
308 COMPONENT::tr_review();
309 if (order() > 0 && _y
[0].f0
!= LINEAR
) {
310 double timestep
= tr_review_trunc_error(_y
);
311 double newtime
= tr_review_check_and_convert(timestep
);
312 _time_by
.min_error_estimate(newtime
);
318 /*--------------------------------------------------------------------------*/
319 void ELEMENT::tr_accept()
321 COMPONENT::tr_accept();
323 for (unsigned int i
=0; i
< matrix_nodes(); ++i
) {
324 _n
[i
]->discont(_discont
);
329 /*--------------------------------------------------------------------------*/
330 void ELEMENT::tr_iwant_matrix_passive()
332 assert(matrix_nodes() == 2);
334 //assert(!subckt()); ok for subckt to exist for logic
335 trace3("ELEMENT::tr_iwant_matrix_passive", long_label().c_str(), _n
[OUT1
].m_(), _n
[OUT2
].m_());
337 if (_n
[OUT1
].m_() == INVALID_NODE
) {
338 std::cerr
<< "ELEMENT::tr_iwant_matrix_passive " << long_label() << "\n";
341 assert(_n
[OUT2
].m_() != INVALID_NODE
);
343 _sim
->_aa
.iwant(_n
[OUT1
].m_(),_n
[OUT2
].m_());
344 _sim
->_lu
.iwant(_n
[OUT1
].m_(),_n
[OUT2
].m_());
346 /*--------------------------------------------------------------------------*/
347 void ELEMENT::tr_iwant_matrix_active()
349 trace3("ELEMENT::tr_iwant_matrix_active", long_label(), _n
[OUT1
].m_(), _n
[OUT2
].m_());
350 assert(matrix_nodes() >= 4);
352 // assert(!subckt());
354 assert(_n
[OUT1
].m_() != INVALID_NODE
);
355 assert(_n
[OUT2
].m_() != INVALID_NODE
);
356 assert(_n
[IN1
].m_() != INVALID_NODE
);
357 assert(_n
[IN2
].m_() != INVALID_NODE
);
359 //_sim->_aa.iwant(_n[OUT1].m_(),_n[OUT2].m_());
360 _sim
->_aa
.iwant(_n
[OUT1
].m_(),_n
[IN1
].m_());
361 _sim
->_aa
.iwant(_n
[OUT1
].m_(),_n
[IN2
].m_());
362 _sim
->_aa
.iwant(_n
[OUT2
].m_(),_n
[IN1
].m_());
363 _sim
->_aa
.iwant(_n
[OUT2
].m_(),_n
[IN2
].m_());
364 //_sim->_aa.iwant(_n[IN1].m_(),_n[IN2].m_());
366 //_sim->_lu.iwant(_n[OUT1].m_(),_n[OUT2].m_());
367 _sim
->_lu
.iwant(_n
[OUT1
].m_(),_n
[IN1
].m_());
368 _sim
->_lu
.iwant(_n
[OUT1
].m_(),_n
[IN2
].m_());
369 _sim
->_lu
.iwant(_n
[OUT2
].m_(),_n
[IN1
].m_());
370 _sim
->_lu
.iwant(_n
[OUT2
].m_(),_n
[IN2
].m_());
371 //_sim->_lu.iwant(_n[IN1].m_(),_n[IN2].m_());
373 /*--------------------------------------------------------------------------*/
374 void ELEMENT::tr_iwant_matrix_extended()
376 trace4("ELEMENT::tr_iwant_matrix_extended", long_label(), dev_type(), ext_nodes(), int_nodes());
378 assert(ext_nodes() + int_nodes() == matrix_nodes());
380 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
381 trace2("ELEMENT::tr_iwant_matrix_extended", ii
, _n
[ii
].m_() );
383 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
384 if (_n
[ii
].m_() != INVALID_NODE
) {
385 for (uint_t jj
= 0; jj
< ii
; ++jj
) {
386 _sim
->_aa
.iwant(_n
[ii
].m_(),_n
[jj
].m_());
387 _sim
->_lu
.iwant(_n
[ii
].m_(),_n
[jj
].m_());
390 // node 1 is grounded or invalid
394 /*--------------------------------------------------------------------------*/
395 void ELEMENT::ac_iwant_matrix_passive()
397 trace2(long_label().c_str(), _n
[OUT1
].m_(), _n
[OUT2
].m_());
398 _sim
->_acx
.iwant(_n
[OUT1
].m_(),_n
[OUT2
].m_());
400 /*--------------------------------------------------------------------------*/
401 void ELEMENT::ac_iwant_matrix_active()
403 //_sim->_acx.iwant(_n[OUT1].m_(),_n[OUT2].m_());
404 _sim
->_acx
.iwant(_n
[OUT1
].m_(),_n
[IN1
].m_());
405 _sim
->_acx
.iwant(_n
[OUT1
].m_(),_n
[IN2
].m_());
406 _sim
->_acx
.iwant(_n
[OUT2
].m_(),_n
[IN1
].m_());
407 _sim
->_acx
.iwant(_n
[OUT2
].m_(),_n
[IN2
].m_());
408 //_sim->_acx.iwant(_n[IN1].m_(),_n[IN2].m_());
410 /*--------------------------------------------------------------------------*/
411 void ELEMENT::ac_iwant_matrix_extended()
414 assert(ext_nodes() + int_nodes() == matrix_nodes());
416 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
417 if (_n
[ii
].m_() !=INVALID_NODE
) {
418 for (uint_t jj
= 0; jj
< ii
; ++jj
) {
419 _sim
->_acx
.iwant(_n
[ii
].m_(),_n
[jj
].m_());
422 // node 1 is grounded or invalid
426 /*--------------------------------------------------------------------------*/
427 hp_float_t
ELEMENT::tr_amps()const
429 hp_float_t root
= fixzero((_loss0
* tr_outvolts() + _m0
.c1
* tr_involts() + _m0
.c0
),
435 /*--------------------------------------------------------------------------*/
436 void ELEMENT::tr_save_amps(int n
){
438 trace2( "ELEMENT::tr_save_amps ", n
, _sim
->_tt_accepted
);
439 hp_float_t tramps
= tr_amps();
441 hp_float_t _tr_amps_diff_cur
;
442 hp_float_t _tr_amps_sum_cur
;
444 if( _amps_new
== 0 ){
445 incomplete(); // somebody forgot to initilize
450 trace3( "saving _amps[ ", n
, net_nodes(), _amps
[n
] );
451 _tr_amps_sum_cur
= fabs( _amps
[n
] ) + fabs( tramps
);
452 _tr_amps_diff_cur
= fabs( _amps
[n
] - tramps
);
453 // std::cerr << "ELEMENT::tr_save_amps: not first. diff= " << _tr_amps_diff_cur << "\n";
455 trace2( "dummy _amps[ ", n
, net_nodes() );
456 _tr_amps_diff_cur
= 0;
457 _tr_amps_sum_cur
= 1;
460 // std::cerr << short_label() << ": saving _amps[ " << n << " ]" << _amps << " \n";
461 trace2( (short_label() + " have ").c_str(), tramps
, n
);
462 _amps_new
[ n
]= tramps
;
465 trace1("ELEMENT::tr_save_amps", _tr_amps_sum_cur
);
466 tr_behaviour_del
= _tr_amps_diff_cur
;
467 tr_behaviour_rel
= _tr_amps_diff_cur
/ _tr_amps_sum_cur
;
470 // tr_behaviour_del = 0;
471 // tr_behaviour_rel = 0;
473 COMPONENT::tr_behaviour();
476 /*--------------------------------------------------------------------------*/
477 double ELEMENT::tr_probe_num(const std::string
& x
)const
479 if (Umatch(x
, "v{out} ")) {
480 return tr_outvolts();
481 }else if (Umatch(x
, "amps_diff ")) {
482 return tr_amps_diff();
483 }else if (Umatch(x
, "vi{n} |v0 ")) {
485 // }else if (Umatch(x, "dv ")) { untested();
486 // return ( _n[OUT2].vt1() - _n[OUT1].vt1() );
487 }else if (Umatch(x
, "v1 ")) {
489 const ELEMENT
* more
= prechecked_cast
<const ELEMENT
*>(*(subckt()->begin()));
490 return more
->tr_involts();
493 }else if (Umatch(x
, "i ")) {
495 }else if (Umatch(x
, "i1 ")) {
496 const ELEMENT
* more
= prechecked_cast
<const ELEMENT
*>(*(subckt()->begin()));
499 return more
->tr_amps();
502 }else if (Umatch(x
, "p ")) {
503 return tr_amps() * tr_outvolts();
504 }else if (Umatch(x
, "pd ")) {
505 double p
= tr_amps() * tr_outvolts();
506 return (p
> 0.) ? p
: 0.;
507 }else if (Umatch(x
, "ps ")) {
508 double p
= tr_amps() * tr_outvolts();
509 return (p
< 0.) ? -p
: 0.;
510 }else if (Umatch(x
, "in{put} ")) {
512 }else if (Umatch(x
, "f ")) {
513 if (_y
[0].f0
== LINEAR
) {itested();
514 return _y
[0].x
* _y
[0].f1
;
518 }else if (Umatch(x
, "ev |df ")) {
520 }else if (Umatch(x
, "dx ")) {
521 return _y1
.x
-_y
[0].x
;
522 }else if (Umatch(x
, "res ")) {
523 return _y1
.f0
-_y
[0].f0
;
524 }else if (Umatch(x
, "conv{erged} ")) {
525 // assert(converged()==conv_check()); no.
526 return converged() + 10*conv_check();
527 }else if (Umatch(x
, "nv ")) {
529 }else if (Umatch(x
, "eiv ")) {untested();
531 }else if (Umatch(x
, "y |m0c1 ")) {
533 }else if (Umatch(x
, "is{tamp} ")) {
535 }else if (Umatch(x
, "iof{fset} ")) {
537 }else if (Umatch(x
, "ip{assive} ")) {itested();
538 return _m0
.c1
* tr_involts();
539 }else if (Umatch(x
, "il{oss} ")) {untested();
540 return _loss0
* tr_outvolts();
541 }else if (Umatch(x
, "dt ")) {
543 }else if (Umatch(x
, "dtr{equired} ")) {
544 return ((_time_by
._error_estimate
- _time
[0]) > 0)
545 ? _time_by
._error_estimate
- _time
[0]
546 : _time_by
._error_estimate
- _time
[1];
547 }else if (Umatch(x
, "time ")) {untested();
549 }else if (Umatch(x
, "timeo{ld} ")) {untested();
551 //}else if (Umatch(x, "didt ")) {untested();
552 //double i0 = (_m0.c1 * _m0.x + _m0.c0);
553 //double it1 = (mt1.f1 * mt1.x + mt1.c0);
554 //return (i0 - it1) / (_sim->_time0 - _time1);
555 }else if (Umatch(x
, "r ")) {
556 return (_m0
.c1
!=0.) ? 1/_m0
.c1
: MAXDBL
;
557 }else if (Umatch(x
, "ic ")) {
558 if (!has_ic()){ untested();
560 } else if (const EVAL_BM_ACTION_BASE
* x
= dynamic_cast<const EVAL_BM_ACTION_BASE
*>(common())) {
562 } else { unreachable();
565 }else if (Umatch(x
, "z ")) {
566 return port_impedance(_n
[OUT1
], _n
[OUT2
], _sim
->_lu
, (double) (mfactor()*(_m0
.c1
+_loss0
)));
568 }else if (Umatch(x
, "mp ")) {
569 return _n
[OUT1
].m_();
570 }else if (Umatch(x
, "mn ")) {
571 return _n
[OUT2
].m_();
573 }else if (Umatch(x
, "common ")) {
575 }else if (Umatch(x
, "treval ")) {
576 return has_tr_eval();
577 }else if (Umatch(x
, "utreval ")) {
578 return using_tr_eval();
579 }else if (Umatch(x
, "zraw ")) {
580 return port_impedance(_n
[OUT1
], _n
[OUT2
], _sim
->_lu
, 0.);
581 }else if (Umatch(x
, "ord{er} ")) {
584 return COMPONENT::tr_probe_num(x
);
587 /*--------------------------------------------------------------------------*/
588 COMPLEX
ELEMENT::ac_amps()const
590 assert(!is_source());
591 return (ac_involts() * _acg
+ ac_outvolts() * (double)_loss0
);
593 /*--------------------------------------------------------------------------*/
594 XPROBE
ELEMENT::ac_probe_ext(const std::string
& x
)const
596 COMPLEX admittance
= (is_source()) ? _loss0
: _acg
+ (double)_loss0
;
598 if (Umatch(x
, "v{out} ")) { /* volts (out) */
599 return XPROBE(ac_outvolts());
600 }else if (Umatch(x
, "vin ")) { /* volts (in) */
601 return XPROBE(ac_involts());
602 }else if (Umatch(x
, "i ")) { /* amps */
603 return XPROBE(ac_amps());
604 }else if (Umatch(x
, "p ")) { /* complex "power" */
605 return XPROBE(ac_outvolts() * conj(ac_amps()), mtREAL
, 10.);
606 }else if (Umatch(x
, "nv ")) {untested(); /* nominal value */
607 return XPROBE(value());
608 }else if (Umatch(x
, "ev ")) { /* effective value */
609 return XPROBE((COMPLEX
)_ev
);
610 }else if (Umatch(x
, "y ")) {
612 return XPROBE(admittance
, mtREAL
);
613 }else if (Umatch(x
, "r ")) { /* complex "resistance" */
614 if (admittance
== 0.) {untested();
615 return XPROBE(MAXDBL
);
617 return XPROBE(1. / admittance
);
619 }else if (Umatch(x
, "z ")) { /* port impedance */
620 return XPROBE(port_impedance(_n
[OUT1
], _n
[OUT2
], _sim
->_acx
, mfactor()*admittance
));
621 }else if (Umatch(x
, "zraw ")) { /* port impedance, raw */
622 return XPROBE(port_impedance(_n
[OUT1
], _n
[OUT2
], _sim
->_acx
, COMPLEX(0.)));
623 }else if (Umatch(x
, "n ")) { /* port noise, raw */
624 return XPROBE(port_noise(_n
[OUT1
], _n
[OUT2
]));
625 }else{ /* bad parameter */
626 return COMPONENT::ac_probe_ext(x
);
629 /*--------------------------------------------------------------------------*/
630 double ELEMENT::tr_review_trunc_error(const FPOLY1
* q
)
633 if (order() >= OPT::_keep_time_steps
- 2) {
634 error_deriv
= OPT::_keep_time_steps
- 1;
635 }else if (order() < 0) {itested();
638 error_deriv
= order()+1;
642 trace1("ELEMENT::tr_review_trunc_error", error_deriv
);
643 trace2("ELEMENT::tr_review_trunc_error", _time
[0], error_deriv
);
644 // if (_time[0] <= _sim->_time0)
645 if (_sim
->analysis_is_tran_restore()) {
647 }else if (_time
[0] == 0.) {
648 // DC, I know nothing
650 }else if (error_deriv
- 1 - OPT::initsc
< 0 || _time
[error_deriv
- 1 - OPT::initsc
] <= 0 ) {
651 // first few steps, I still know nothing
652 // repeat whatever step was used the first time
655 for (int i
=error_deriv
-1; i
>0; --i
) {
656 assert(_time
[i
] < _time
[i
-1]); // || _time[i] == 0.);
659 double c
[OPT::_keep_time_steps
];
660 for (int i
=0; i
<OPT::_keep_time_steps
; ++i
) {
663 assert(error_deriv
< OPT::_keep_time_steps
);
665 // better use divdiff.
666 // better, only compute up to error_div
667 if (error_deriv
&& 0. == _time
[error_deriv
-1]) {
668 // vile hack, probably not a good idea
669 _time
[error_deriv
] = -_time
[error_deriv
-2];
670 derivatives(c
, OPT::_keep_time_steps
, _time
);
671 _time
[error_deriv
] = 0;
673 derivatives(c
, OPT::_keep_time_steps
, _time
);
675 // now c[i] is i'th derivative
677 assert(OPT::_keep_time_steps
>= 5);
678 trace0(("ts" + long_label()).c_str());
679 trace5("time", _time
[0], _time
[1], _time
[2], _time
[3], _time
[4]);
680 trace5("charge", q
[0].f0
, q
[1].f0
, q
[2].f0
, q
[3].f0
, q
[4].f0
);
681 trace5("deriv", c
[0], c
[1], c
[2], c
[3], c
[4]);
683 if (c
[error_deriv
] == 0) {
686 double chargetol
= std::max(OPT::chgtol
,
687 OPT::reltol
* std::max((double)std::abs(q
[0].f0
), (double) std::abs(q
[1].f0
)));
688 double tol
= OPT::trtol
* chargetol
;
689 double denom
= error_factor() * std::abs(c
[error_deriv
]);
692 switch (error_deriv
) { // pow is slow.
693 case 1: timestep
= tol
/ denom
; break;
694 case 2: timestep
= sqrt(tol
/ denom
); break;
695 case 3: timestep
= cbrt(tol
/ denom
); break;
696 default: timestep
= pow((tol
/ denom
), 1./(error_deriv
)); break;
698 trace4("", chargetol
, tol
, denom
, timestep
);
701 assert(timestep
> 0.);
704 /*--------------------------------------------------------------------------*/
705 double ELEMENT::tr_review_check_and_convert(double timestep
)
708 if (timestep
== NEVER
) {
711 if (timestep
< _sim
->_dtmin
) {
712 timestep
= _sim
->_dtmin
;
716 if (timestep
< _dt
* OPT::trreject
) {
717 if (_time
[order()] == 0) {
718 error(bTRACE
, "initial step rejected:" + long_label() + '\n');
719 error(bTRACE
, "new=%g old=%g required=%g\n",
720 timestep
, _dt
, _dt
* OPT::trreject
);
722 error(bTRACE
, "step rejected:" + long_label() + '\n');
723 error(bTRACE
, "new=%g old=%g required=%g\n",
724 timestep
, _dt
, _dt
* OPT::trreject
);
726 time_future
= _time
[1] + timestep
;
727 trace3("reject", timestep
, _dt
, time_future
);
729 time_future
= _time
[0] + timestep
;
730 trace3("accept", timestep
, _dt
, time_future
);
733 assert(time_future
> 0.);
734 assert(time_future
> _time
[1]);
737 /*--------------------------------------------------------------------------*/
738 void ELEMENT::set_ic(double x
)
741 trace1("ELEMENT::set_ic " + long_label(), x
);
742 *(_value
.pointer_hack()) = x
;
748 /*--------------------------------------------------------------------------*/
749 void ELEMENT::keep_ic()
753 /*--------------------------------------------------------------------------*/
754 void ELEMENT::tt_advance()
756 trace3("ELEMENT::tt_advance", short_label(), _sim
->_time0
, _sim
->_dt0
);
758 for (int i
=0; i
<OPT::_keep_time_steps
-1; ++i
) {
762 _time
[OPT::_keep_time_steps
-1] = 0.;
763 _y
[OPT::_keep_time_steps
-1] = FPOLY1(0., 0., 0.);
764 }else if (_time
[0] == _sim
->_time0
) {
768 for (int i
=OPT::_keep_time_steps
-1; i
>=0; --i
) {
772 /*--------------------------------------------------------------------------*/
773 // hmmmm like tr_begin? start from scratch?
774 void ELEMENT::tt_regress()
776 assert(_sim
->_time0
== 0.);
777 trace3("ELEMENT::tt_regress", short_label(), _sim
->_time0
, _sim
->_dt0
);
778 if (_time
[0] > _sim
->_time0
) {
779 for (int i
=0; i
<OPT::_keep_time_steps
-1; ++i
) {
783 _time
[OPT::_keep_time_steps
-1] = 0.;
784 _y
[OPT::_keep_time_steps
-1] = FPOLY1(0., 0., 0.);
785 }else if (_time
[0] == _sim
->_time0
) {
791 for (int i
=OPT::_keep_time_steps
-1; i
>=0; --i
) {
795 /*--------------------------------------------------------------------------*/
796 // probably ineffective?
797 void ELEMENT::set_param_by_name(string Name
, string Value
)
799 trace3("ELEMENT::set_param_by_name", Name
, Value
, value_name());
800 bool isvalue
= false;
801 if(value_name() == "") {
802 }else if(Umatch(Name
,value_name())) {
809 COMMON_COMPONENT
* c
= mutable_common()->clone();
811 c
->set_param_by_name(Name
,Value
);
812 }catch(Exception_No_Match
){
818 if(isvalue
){ itested();
819 c
->set_modelname(Value
);
822 }else if (Umatch (Name
,"type")) { untested();
823 COMMON_COMPONENT
* c
= bm_dispatcher
[Value
];
824 if(!c
) throw Exception_No_Match(Value
);
825 attach_common(c
->clone());
827 COMPONENT::set_param_by_name(Name
,Value
);
830 /*--------------------------------------------------------------------------*/
831 string
ELEMENT::dev_type()const
834 return common()->modelname();
836 return element_type();
839 /*--------------------------------------------------------------------------*/
840 /*--------------------------------------------------------------------------*/
841 /*--------------------------------------------------------------------------*/
842 // vim:ts=8:sw=2:noet: