1 /*$Id: e_storag.cc,v 26.132 2009/11/24 04:26:37 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)
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 storage elements of a circuit
24 //testing=obsolete,script 2006.06.14
26 /*--------------------------------------------------------------------------*/
27 /* table for selecting local integraton method
28 * Determines which one wins in a conflict.
29 * "only" wins over non-only. local (_method_u) wins over opt.
31 // OPT::method _method_u
32 METHOD
STORAGE::method_select
[meNUM_METHODS
][meNUM_METHODS
] = {
34 //local>>>EULER,EULERONLY,TRAP,TRAPONLY,GEAR2,GEAR2ONLY,TRAPGEAR,TRAPEULER
36 {mTRAPGEAR
,mEULER
,mEULER
,mTRAP
, mTRAP
,mGEAR
, mGEAR
,mTRAPGEAR
,mTRAPEULER
},
38 {mEULER
, mEULER
,mEULER
,mTRAP
, mTRAP
,mGEAR
, mGEAR
,mTRAPGEAR
,mTRAPEULER
},
40 {mEULER
, mEULER
,mEULER
,mEULER
,mTRAP
,mEULER
,mGEAR
,mEULER
, mEULER
},
42 {mTRAP
, mEULER
,mEULER
,mTRAP
, mTRAP
,mGEAR
, mGEAR
,mTRAPGEAR
,mTRAPEULER
},
44 {mTRAP
, mTRAP
, mEULER
,mTRAP
, mTRAP
,mTRAP
, mGEAR
,mTRAP
, mTRAP
},
46 {mGEAR
, mEULER
,mEULER
,mTRAP
, mTRAP
,mGEAR
, mGEAR
,mTRAPGEAR
,mTRAPEULER
},
48 {mGEAR
, mGEAR
, mEULER
,mGEAR
, mTRAP
,mGEAR
, mGEAR
,mGEAR
, mGEAR
},
50 {mTRAPGEAR
,mEULER
,mEULER
,mTRAP
, mTRAP
,mGEAR
, mGEAR
,mTRAPGEAR
,mTRAPEULER
},
52 {mTRAPEULER
,mEULER
,mEULER
,mTRAP
,mTRAP
,mGEAR
, mGEAR
,mTRAPGEAR
,mTRAPEULER
}
54 /*--------------------------------------------------------------------------*/
55 void STORAGE::precalc_last()
57 ELEMENT::precalc_last();
60 assert(!is_constant()); /* because of integration */
62 _method_a
= method_select
[OPT::method
][_method_u
];
63 //assert(_loss0 == 0.);
64 //assert(_loss1 == 0.);
65 /* m0 and acg are frequency/time dependent and cannot be set here.
66 * If this is a coupled inductor, there is a subckt, which is expanded
67 * by the mutual pseudo-element.
68 * Assigning the values here becomes unnecessary, but harmless.
71 /*--------------------------------------------------------------------------*/
72 void STORAGE::tr_begin()
75 _method_a
= method_select
[OPT::method
][_method_u
];
76 for (int i
= 0; i
< OPT::_keep_time_steps
; ++i
) {
77 _i
[i
] = FPOLY1(0., 0., 0.);
79 _m1
= _m0
= CPOLY1(0., 0., 0.);
81 /*--------------------------------------------------------------------------*/
82 void STORAGE::tr_restore()
84 ELEMENT::tr_restore();
85 _method_a
= method_select
[OPT::method
][_method_u
];
87 /*--------------------------------------------------------------------------*/
88 void STORAGE::dc_advance()
90 ELEMENT::dc_advance();
92 for (int i
= 1; i
< OPT::_keep_time_steps
; ++i
) {
96 /*--------------------------------------------------------------------------*/
97 void STORAGE::tr_advance()
99 ELEMENT::tr_advance();
101 for (int i
=OPT::_keep_time_steps
-1; i
>0; --i
) {
105 /*--------------------------------------------------------------------------*/
106 /* tr_needs_eval: check to see if this device needs to be evaluated
107 * this works, and saves significant time
108 * but possible errors.
109 * Errors do not seem significant, but I can't tell without more data.
110 * To disable: option nolcbypass
112 bool STORAGE::tr_needs_eval()const
114 //assert(!is_q_for_eval());
115 return (!OPT::lcbypass
117 || _sim
->is_advance_or_first_iteration()
118 || !conchk(_y
[0].x
, tr_input(), OPT::abstol
)
121 /*--------------------------------------------------------------------------*/
122 /* differentiate: this is what Spice calls "integrate".
123 * returns an approximation of the time derivative of _q,
124 * where _q is an array of states .. charge for capacitors, flux for inductors.
125 * return value is current for capacitors, volts for inductors.
127 FPOLY1
differentiate(const FPOLY1
* q
, const FPOLY1
* i
, double* time
, METHOD method
)
129 if (CKT_BASE::_sim
->analysis_is_static()) {
130 assert(time
[0] == 0.);
131 return FPOLY1(q
[0].x
, 0., 0.);
132 }else if (CKT_BASE::_sim
->analysis_is_restore()) {
133 /* leave it alone to restart from a previous solution */
134 /* it goes this way to continue a transient analysis */
138 assert(CKT_BASE::_sim
->analysis_is_tran_dynamic());
140 method
= mEULER
; // Bogus current in previous step. Force Euler.
143 double dt
= time
[0] - time
[1];
149 assert(OPT::_keep_time_steps
>= 3);
150 return FPOLY1(q
[0].x
,
151 (3./2.) * (q
[0].f0
- q
[1].f0
) / dt
152 - (1./2.) * (q
[1].f0
- q
[2].f0
) / (time
[1] - time
[2]),
153 q
[0].f1
* (3./2.) / dt
);
157 assert(OPT::_keep_time_steps
>= 2);
158 return FPOLY1(q
[0].x
,
159 (q
[0].f0
- q
[1].f0
) / dt
,
162 assert(OPT::_keep_time_steps
>= 2);
163 return FPOLY1(q
[0].x
,
164 2 * (q
[0].f0
- q
[1].f0
) / dt
- i
[1].f0
,
172 /*--------------------------------------------------------------------------*/
173 double STORAGE::tr_c_to_g(double c
, double g
)const
175 if (_sim
->analysis_is_static()) {
176 assert(_time
[0] == 0.);
178 }else if (_sim
->analysis_is_restore()) {itested();
179 assert(_time
[0] > 0);
183 assert(_sim
->analysis_is_tran_dynamic());
186 method
= mEULER
; // Bogus current in previous step. Force Euler.
192 case mTRAPGEAR
: incomplete();
193 case mGEAR
: g
*= 3./2.; break;
194 case mTRAPEULER
: incomplete();
195 case mEULER
: /* g *= 1 */ break;
196 case mTRAP
: g
*= 2; break;
201 /*--------------------------------------------------------------------------*/
202 TIME_PAIR
STORAGE::tr_review()
204 COMPONENT::tr_review(); // skip ELEMENT
205 if (_method_a
== mEULER
) {
206 // Backward Euler, no step control, take it as it comes
208 double timestep
= tr_review_trunc_error(_y
);
209 _time_by
.min_error_estimate(tr_review_check_and_convert(timestep
));
213 /*--------------------------------------------------------------------------*/
214 double STORAGE::tr_probe_num(const std::string
& x
)const
216 if (Umatch(x
, "method ")) {untested();
217 return static_cast<double>(_method_a
);
219 return ELEMENT::tr_probe_num(x
);
222 /*--------------------------------------------------------------------------*/
223 /*--------------------------------------------------------------------------*/
224 // vim:ts=8:sw=2:noet: