My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
trsolver.cpp
Go to the documentation of this file.
1 /*
2  * trsolver.cpp - transient solver class implementation
3  *
4  * Copyright (C) 2004, 2005, 2006, 2007, 2009 Stefan Jahn <stefan@lkcc.org>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id: trsolver.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 #include <float.h>
33 
34 #include "compat.h"
35 #include "object.h"
36 #include "logging.h"
37 #include "complex.h"
38 #include "circuit.h"
39 #include "sweep.h"
40 #include "net.h"
41 #include "netdefs.h"
42 #include "analysis.h"
43 #include "nasolver.h"
44 #include "history.h"
45 #include "trsolver.h"
46 #include "transient.h"
47 #include "exception.h"
48 #include "exceptionstack.h"
49 
50 #define STEPDEBUG 0 // set to zero for release
51 #define BREAKPOINTS 0 // exact breakpoint calculation
52 
53 #define dState 0 // delta T state
54 #define sState 1 // solution state
55 
56 using namespace transient;
57 
58 // Constructor creates an unnamed instance of the trsolver class.
60  : nasolver<nr_double_t> (), states<nr_double_t> () {
61  swp = NULL;
62  type = ANALYSIS_TRANSIENT;
63  setDescription ("transient");
64  for (int i = 0; i < 8; i++) solution[i] = NULL;
65  tHistory = NULL;
66  relaxTSR = false;
67  initialDC = true;
68 }
69 
70 // Constructor creates a named instance of the trsolver class.
72  : nasolver<nr_double_t> (n), states<nr_double_t> () {
73  swp = NULL;
75  setDescription ("transient");
76  for (int i = 0; i < 8; i++) solution[i] = NULL;
77  tHistory = NULL;
78  relaxTSR = false;
79  initialDC = true;
80 }
81 
82 // Destructor deletes the trsolver class object.
84  if (swp) delete swp;
85  for (int i = 0; i < 8; i++) if (solution[i] != NULL) delete solution[i];
86  if (tHistory) delete tHistory;
87 }
88 
89 /* The copy constructor creates a new instance of the trsolver class
90  based on the given trsolver object. */
92  : nasolver<nr_double_t> (o), states<nr_double_t> (o) {
93  swp = o.swp ? new sweep (*o.swp) : NULL;
94  for (int i = 0; i < 8; i++) solution[i] = NULL;
95  tHistory = o.tHistory ? new history (*o.tHistory) : NULL;
96  relaxTSR = o.relaxTSR;
97  initialDC = o.initialDC;
98 }
99 
100 // This function creates the time sweep if necessary.
101 void trsolver::initSteps (void) {
102  if (swp != NULL) delete swp;
103  swp = createSweep ("time");
104 }
105 
106 // Macro for the n-th state of the solution vector history.
107 #define SOL(state) (solution[(int) getState (sState, (state))])
108 
109 
110 // Performs the initial DC analysis.
112  int error = 0;
113 
114  // First calculate a initial state using the non-linear DC analysis.
115  setDescription ("initial DC");
116  initDC ();
118  solve_pre ();
119  applyNodeset ();
120 
121  // Run the DC solver once.
122  try_running () {
123  error = solve_nonlinear ();
124  }
125  // Appropriate exception handling.
126  catch_exception () {
128  pop_exception ();
130  logprint (LOG_ERROR, "WARNING: %s: %s analysis failed, using line search "
131  "fallback\n", getName (), getDescription ());
132  applyNodeset ();
133  restart ();
134  error = solve_nonlinear ();
135  break;
136  default:
137  // Otherwise return.
138  estack.print ();
139  error++;
140  break;
141  }
142 
143  // Save the DC solution.
144  storeSolution ();
145 
146  // Cleanup nodal analysis solver.
147  solve_post ();
148 
149  // Really failed to find initial DC solution?
150  if (error) {
151  logprint (LOG_ERROR, "ERROR: %s: %s analysis failed\n",
152  getName (), getDescription ());
153  }
154  return error;
155 }
156 
157 /* This is the transient netlist solver. It prepares the circuit list
158  for each requested time and solves it then. */
159 int trsolver::solve (void) {
160  nr_double_t time, saveCurrent;
161  int error = 0, convError = 0;
162  char * solver = getPropertyString ("Solver");
163  relaxTSR = !strcmp (getPropertyString ("relaxTSR"), "yes") ? true : false;
164  initialDC = !strcmp (getPropertyString ("initialDC"), "yes") ? true : false;
165 
166  runs++;
167  saveCurrent = current = 0;
168  stepDelta = -1;
169  converged = 0;
170  fixpoint = 0;
171  statRejected = statSteps = statIterations = statConvergence = 0;
172 
173  // Choose a solver.
174  if (!strcmp (solver, "CroutLU"))
176  else if (!strcmp (solver, "DoolittleLU"))
178  else if (!strcmp (solver, "HouseholderQR"))
180  else if (!strcmp (solver, "HouseholderLQ"))
182  else if (!strcmp (solver, "GolubSVD"))
184 
185  // Perform initial DC analysis.
186  if (initialDC) {
187  error = dcAnalysis ();
188  if (error)
189  return -1;
190  }
191 
192  // Initialize transient analysis.
193  setDescription ("transient");
194  initTR ();
196  solve_pre ();
197 
198  // Create time sweep if necessary.
199  initSteps ();
200  swp->reset ();
201 
202  // Recall the DC solution.
203  recallSolution ();
204 
205  // Apply the nodesets and adjust previous solutions.
206  applyNodeset (false);
207  fillSolution (x);
208 
209  // Tell integrators to be initialized.
210  setMode (MODE_INIT);
211 
212  int running = 0;
213  rejected = 0;
214  delta /= 10;
215  fillState (dState, delta);
216  adjustOrder (1);
217 
218  // Start to sweep through time.
219  for (int i = 0; i < swp->getSize (); i++) {
220  time = swp->next ();
221  if (progress) logprogressbar (i, swp->getSize (), 40);
222 
223 #if DEBUG && 0
224  logprint (LOG_STATUS, "NOTIFY: %s: solving netlist for t = %e\n",
225  getName (), (double) time);
226 #endif
227 
228  do {
229 #if STEPDEBUG
230  if (delta == deltaMin) {
232  "WARNING: %s: minimum delta h = %.3e at t = %.3e\n",
233  getName (), (double) delta, (double) current);
234  }
235 #endif
236  updateCoefficients (delta);
237 
238  // Run predictor.
239  error += predictor ();
240 
241  // restart Newton iteration
242  if (rejected) {
243  restart (); // restart non-linear devices
244  rejected = 0;
245  }
246 
247  // Run corrector process.
248  try_running () {
249  error += corrector ();
250  }
251  // Appropriate exception handling.
252  catch_exception () {
254  pop_exception ();
255 
256  // Reduce step-size if failed to converge.
257  if (current > 0) current -= delta;
258  delta /= 2;
259  if (delta <= deltaMin) {
260  delta = deltaMin;
261  adjustOrder (1);
262  }
263  if (current > 0) current += delta;
264 
265  // Update statistics.
266  statRejected++;
267  statConvergence++;
268  rejected++;
269  converged = 0;
270  error = 0;
271 
272  // Start using damped Newton-Raphson.
274  convError = 2;
275 
276 #if DEBUG
277  logprint (LOG_ERROR, "WARNING: delta rejected at t = %.3e, h = %.3e "
278  "(no convergence)\n", (double) saveCurrent, (double) delta);
279 #endif
280  break;
281  default:
282  // Otherwise return.
283  estack.print ();
284  error++;
285  break;
286  }
287  if (error) return -1;
288  if (rejected) continue;
289 
290  // check whether Jacobian matrix is still non-singular
291  if (!A->isFinite ()) {
292  logprint (LOG_ERROR, "ERROR: %s: Jacobian singular at t = %.3e, "
293  "aborting %s analysis\n", getName (), (double) current,
294  getDescription ());
295  return -1;
296  }
297 
298  // Update statistics and no more damped Newton-Raphson.
299  statIterations += iterations;
300  if (--convError < 0) convHelper = 0;
301 
302  // Now advance in time or not...
303  if (running > 1) {
304  adjustDelta (time);
305  adjustOrder ();
306  }
307  else {
308  fillStates ();
309  nextStates ();
310  rejected = 0;
311  }
312 
313  saveCurrent = current;
314  current += delta;
315  running++;
316  converged++;
317 
318  // Tell integrators to be running.
319  setMode (MODE_NONE);
320 
321  // Initialize or update history.
322  if (running > 1) {
323  updateHistory (saveCurrent);
324  }
325  else {
326  initHistory (saveCurrent);
327  }
328  }
329  while (saveCurrent < time); // Hit a requested time point?
330 
331  // Save results.
332 #if STEPDEBUG
333  logprint (LOG_STATUS, "DEBUG: save point at t = %.3e, h = %.3e\n",
334  (double) saveCurrent, (double) delta);
335 #endif
336 
337 #if BREAKPOINTS
338  saveAllResults (saveCurrent);
339 #else
340  saveAllResults (time);
341 #endif
342  }
343  solve_post ();
344  if (progress) logprogressclear (40);
345  logprint (LOG_STATUS, "NOTIFY: %s: average time-step %g, %d rejections\n",
346  getName (), (double) (saveCurrent / statSteps), statRejected);
347  logprint (LOG_STATUS, "NOTIFY: %s: average NR-iterations %g, "
348  "%d non-convergences\n", getName (),
349  (double) statIterations / statSteps, statConvergence);
350 
351  // cleanup
352  deinitTR ();
353  return 0;
354 }
355 
356 // The function initializes the history.
357 void trsolver::initHistory (nr_double_t t) {
358  // initialize time vector
359  tHistory = new history ();
360  tHistory->append (t);
361  tHistory->self ();
362  // initialize circuit histories
363  nr_double_t age = 0.0;
364  circuit * root = subnet->getRoot ();
365  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
366  if (c->hasHistory ()) {
367  c->applyHistory (tHistory);
368  saveHistory (c);
369  if (c->getHistoryAge () > age) age = c->getHistoryAge ();
370  }
371  }
372  // set maximum required age for all circuits
373  tHistory->setAge (age);
374 }
375 
376 /* The following function updates the histories for the circuits which
377  requested them. */
378 void trsolver::updateHistory (nr_double_t t) {
379  if (t > tHistory->last ()) {
380  // update time vector
381  tHistory->append (t);
382  // update circuit histories
383  circuit * root = subnet->getRoot ();
384  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
385  if (c->hasHistory ()) saveHistory (c);
386  }
387  tHistory->drop ();
388  }
389 }
390 
391 // Stores node voltages and branch currents in the given circuits history.
393  int N = countNodes ();
394  int r, i, s = c->getSize ();
395  for (i = 0; i < s; i++) {
396  // save node voltages
397  r = findAssignedNode (c, i);
398  if (r < 0)
399  c->appendHistory (i, 0.0);
400  else
401  c->appendHistory (i, x->get (r));
402  }
403  for (i = 0; i < c->getVoltageSources (); i++) {
404  // save branch currents
405  r = c->getVoltageSource () + i;
406  c->appendHistory (i + s, x->get (r + N));
407  }
408 }
409 
410 /* This function predicts a start value for the solution vector for
411  the successive iterative corrector process. */
413  int error = 0;
414  switch (predType) {
415  case INTEGRATOR_GEAR: // explicit GEAR
416  predictGear ();
417  break;
418  case INTEGRATOR_ADAMSBASHFORD: // ADAMS-BASHFORD
419  predictBashford ();
420  break;
421  case INTEGRATOR_EULER: // FORWARD EULER
422  predictEuler ();
423  break;
424  default:
425  *x = *SOL (1); // This is too a simple predictor...
426  break;
427  }
428  saveSolution ();
429  *SOL (0) = *x;
430  return error;
431 }
432 
433 // Stores the given vector into all the solution vectors.
435  for (int i = 0; i < 8; i++) *SOL (i) = *s;
436 }
437 
438 /* The function predicts the successive solution vector using the
439  explicit Adams-Bashford integration formula. */
441  int N = countNodes ();
442  int M = countVoltageSources ();
443  nr_double_t xn, dd, hn;
444 
445  // go through each solution
446  for (int r = 0; r < N + M; r++) {
447  xn = predCoeff[0] * SOL(1)->get (r); // a0 coefficient
448  for (int o = 1; o <= predOrder; o++) {
449  hn = getState (dState, o); // previous time-step
450  // divided differences
451  dd = (SOL(o)->get (r) - SOL(o + 1)->get (r)) / hn;
452  xn += predCoeff[o] * dd; // b0, b1, ... coefficients
453  }
454  x->set (r, xn); // save prediction
455  }
456 }
457 
458 /* The function predicts the successive solution vector using the
459  explicit forward Euler integration formula. Actually this is
460  Adams-Bashford order 1. */
462  int N = countNodes ();
463  int M = countVoltageSources ();
464  nr_double_t xn, dd, hn;
465 
466  for (int r = 0; r < N + M; r++) {
467  xn = predCoeff[0] * SOL(1)->get (r);
468  hn = getState (dState, 1);
469  dd = (SOL(1)->get (r) - SOL(2)->get (r)) / hn;
470  xn += predCoeff[1] * dd;
471  x->set (r, xn);
472  }
473 }
474 
475 /* The function predicts the successive solution vector using the
476  explicit Gear integration formula. */
478  int N = countNodes ();
479  int M = countVoltageSources ();
480  nr_double_t xn;
481 
482  // go through each solution
483  for (int r = 0; r < N + M; r++) {
484  xn = 0;
485  for (int o = 0; o <= predOrder; o++) {
486  // a0, a1, ... coefficients
487  xn += predCoeff[o] * SOL(o + 1)->get (r);
488  }
489  x->set (r, xn); // save prediction
490  }
491 }
492 
493 /* The function iterates through the solutions of the integration
494  process until a certain error tolerance has been reached. */
496  int error = 0;
497  error += solve_nonlinear ();
498  return error;
499 }
500 
501 // The function advances one more time-step.
502 void trsolver::nextStates (void) {
503  circuit * root = subnet->getRoot ();
504  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
505  c->nextState ();
506  *SOL (0) = *x; // save current solution
507  nextState ();
508  statSteps++;
509 }
510 
511 /* This function stores the current state of each circuit into all
512  other states as well. It is useful for higher order integration
513  methods in order to initialize the states after the initial
514  transient solution. */
515 void trsolver::fillStates (void) {
516  circuit * root = subnet->getRoot ();
517  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
518  for (int s = 0; s < c->getStates (); s++)
519  c->fillState (s, c->getState (s));
520  }
521 }
522 
523 // The function modifies the circuit lists integrator mode.
524 void trsolver::setMode (int state) {
525  circuit * root = subnet->getRoot ();
526  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
527  c->setMode (state);
528 }
529 
530 // The function passes the time delta array to the circuit list.
531 void trsolver::setDelta (void) {
532  circuit * root = subnet->getRoot ();
533  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
534  c->setDelta (deltas);
535 }
536 
537 /* This function tries to adapt the current time-step according to the
538  global truncation error. */
539 void trsolver::adjustDelta (nr_double_t t) {
540  deltaOld = delta;
541  delta = checkDelta ();
542  if (delta > deltaMax) delta = deltaMax;
543  if (delta < deltaMin) delta = deltaMin;
544 
545  // delta correction in order to hit exact breakpoint
546  int good = 0;
547  if (!relaxTSR) { // relaxed step raster?
548  if (!statConvergence || converged > 64) { /* Is this a good guess? */
549  // check next breakpoint
550  if (stepDelta > 0.0) {
551  // restore last valid delta
552  delta = stepDelta;
553  stepDelta = -1.0;
554  }
555  else {
556  if (delta > (t - current) && t > current) {
557  // save last valid delta and set exact step
558  stepDelta = deltaOld;
559  delta = t - current;
560  good = 1;
561  }
562  else {
563  stepDelta = -1.0;
564  }
565  }
566  if (delta > deltaMax) delta = deltaMax;
567  if (delta < deltaMin) delta = deltaMin;
568  }
569  }
570 
571  // usual delta correction
572  if (delta > 0.9 * deltaOld || good) { // accept current delta
573  nextStates ();
574  rejected = 0;
575 #if STEPDEBUG
577  "DEBUG: delta accepted at t = %.3e, h = %.3e\n",
578  (double) current, (double) delta);
579 #endif
580  }
581  else if (deltaOld > delta) { // reject current delta
582  rejected++;
583  statRejected++;
584 #if STEPDEBUG
586  "DEBUG: delta rejected at t = %.3e, h = %.3e\n",
587  (double) current, (double) delta);
588 #endif
589  if (current > 0) current -= deltaOld;
590  }
591  else {
592  nextStates ();
593  rejected = 0;
594  }
595 }
596 
597 /* The function can be used to increase the current order of the
598  integration method or to reduce it. */
599 void trsolver::adjustOrder (int reduce) {
600  if ((corrOrder < corrMaxOrder && !rejected) || reduce) {
601  if (reduce) {
602  corrOrder = 1;
603  } else if (!rejected) {
604  corrOrder++;
605  }
606 
607  // adjust type and order of corrector and predictor
608  corrType = correctorType (CMethod, corrOrder);
609  predType = predictorType (corrType, corrOrder, predOrder);
610 
611  // apply new corrector method and order to each circuit
612  circuit * root = subnet->getRoot ();
613  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
614  c->setOrder (corrOrder);
615  setIntegrationMethod (c, corrType);
616  }
617  }
618 }
619 
620 /* Goes through the list of circuit objects and runs its calcDC()
621  function. */
622 void trsolver::calcDC (trsolver * self) {
623  circuit * root = self->getNet()->getRoot ();
624  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
625  c->calcDC ();
626  }
627 }
628 
629 /* Goes through the list of circuit objects and runs its calcTR()
630  function. */
631 void trsolver::calcTR (trsolver * self) {
632  circuit * root = self->getNet()->getRoot ();
633  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
634  c->calcTR (self->current);
635  }
636 }
637 
638 /* Goes through the list of non-linear circuit objects and runs its
639  restartDC() function. */
640 void trsolver::restart (void) {
641  circuit * root = subnet->getRoot ();
642  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
643  if (c->isNonLinear ()) c->restartDC ();
644  }
645 }
646 
647 /* Goes through the list of circuit objects and runs its initDC()
648  function. */
649 void trsolver::initDC (void) {
650  circuit * root = subnet->getRoot ();
651  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
652  c->initDC ();
653  }
654 }
655 
656 /* Goes through the list of circuit objects and runs its initTR()
657  function. */
658 void trsolver::initTR (void) {
659  char * IMethod = getPropertyString ("IntegrationMethod");
660  nr_double_t start = getPropertyDouble ("Start");
661  nr_double_t stop = getPropertyDouble ("Stop");
662  nr_double_t points = getPropertyDouble ("Points");
663 
664  // fetch corrector integration method and determine predicor method
665  corrMaxOrder = getPropertyInteger ("Order");
666  corrType = CMethod = correctorType (IMethod, corrMaxOrder);
667  predType = PMethod = predictorType (CMethod, corrMaxOrder, predMaxOrder);
668  corrOrder = corrMaxOrder;
669  predOrder = predMaxOrder;
670 
671  // initialize step values
672  delta = getPropertyDouble ("InitialStep");
673  deltaMin = getPropertyDouble ("MinStep");
674  deltaMax = getPropertyDouble ("MaxStep");
675  if (deltaMax == 0.0)
676  deltaMax = MIN ((stop - start) / (points - 1), stop / 200);
677  if (deltaMin == 0.0)
678  deltaMin = NR_TINY * 10 * deltaMax;
679  if (delta == 0.0)
680  delta = MIN (stop / 200, deltaMax) / 10;
681  if (delta < deltaMin) delta = deltaMin;
682  if (delta > deltaMax) delta = deltaMax;
683 
684  // initialize step history
685  setStates (2);
686  initStates ();
687  fillState (dState, delta);
688 
689  saveState (dState, deltas);
690  setDelta ();
691  calcCorrectorCoeff (corrType, corrOrder, corrCoeff, deltas);
692  calcPredictorCoeff (predType, predOrder, predCoeff, deltas);
693 
694  // initialize history of solution vectors (solutions)
695  for (int i = 0; i < 8; i++) {
696  solution[i] = new tvector<nr_double_t>;
697  setState (sState, (nr_double_t) i, i);
698  }
699 
700  // tell circuits about the transient analysis
701  circuit *c, * root = subnet->getRoot ();
702  for (c = root; c != NULL; c = (circuit *) c->getNext ())
703  initCircuitTR (c);
704  // also initialize created circuits
705  for (c = root; c != NULL; c = (circuit *) c->getPrev ())
706  initCircuitTR (c);
707 }
708 
709 // This function cleans up some memory used by the transient analysis.
710 void trsolver::deinitTR (void) {
711  // cleanup solutions
712  for (int i = 0; i < 8; i++) {
713  delete solution[i];
714  solution[i] = NULL;
715  }
716  // cleanup history
717  if (tHistory) {
718  delete tHistory;
719  tHistory = NULL;
720  }
721 }
722 
723 // The function initialize a single circuit.
725  c->initTR ();
726  c->initStates ();
727  c->setCoefficients (corrCoeff);
728  c->setOrder (corrOrder);
729  setIntegrationMethod (c, corrType);
730 }
731 
732 /* This function saves the results of a single solve() functionality
733  (for the given timestamp) into the output dataset. */
734 void trsolver::saveAllResults (nr_double_t time) {
735  vector * t;
736  // add current frequency to the dependency of the output dataset
737  if ((t = data->findDependency ("time")) == NULL) {
738  t = new vector ("time");
739  data->addDependency (t);
740  }
741  if (runs == 1) t->add (time);
742  saveResults ("Vt", "It", 0, t);
743 }
744 
745 /* This function is meant to adapt the current time-step the transient
746  analysis advanced. For the computation of the new time-step the
747  truncation error depending on the integration method is used. */
748 nr_double_t trsolver::checkDelta (void) {
749  nr_double_t LTEreltol = getPropertyDouble ("LTEreltol");
750  nr_double_t LTEabstol = getPropertyDouble ("LTEabstol");
751  nr_double_t LTEfactor = getPropertyDouble ("LTEfactor");
752  nr_double_t dif, rel, tol, lte, q, n = NR_MAX;
753  int N = countNodes ();
754  int M = countVoltageSources ();
755 
756  // cec = corrector error constant
757  nr_double_t cec = getCorrectorError (corrType, corrOrder);
758  // pec = predictor error constant
759  nr_double_t pec = getPredictorError (predType, predOrder);
760 
761  // go through each solution
762  for (int r = 0; r < N + M; r++) {
763 
764  // skip real voltage sources
765  if (r >= N) {
766  if (findVoltageSource(r - N)->isVSource ())
767  continue;
768  }
769 
770  dif = x->get (r) - SOL(0)->get (r);
771  if (finite (dif) && dif != 0) {
772  // use Milne' estimate for the local truncation error
773  rel = MAX (fabs (x->get (r)), fabs (SOL(0)->get (r)));
774  tol = LTEreltol * rel + LTEabstol;
775  lte = LTEfactor * (cec / (pec - cec)) * dif;
776  q = delta * exp (log (fabs (tol / lte)) / (corrOrder + 1));
777  n = MIN (n, q);
778  }
779  }
780 #if STEPDEBUG
781  logprint (LOG_STATUS, "DEBUG: delta according to local truncation "
782  "error h = %.3e\n", (double) n);
783 #endif
784  delta = MIN ((n > 1.9 * delta) ? 2 * delta : delta, n);
785  return delta;
786 }
787 
788 // The function updates the integration coefficients.
789 void trsolver::updateCoefficients (nr_double_t delta) {
790  setState (dState, delta);
791  saveState (dState, deltas);
792  calcCorrectorCoeff (corrType, corrOrder, corrCoeff, deltas);
793  calcPredictorCoeff (predType, predOrder, predCoeff, deltas);
794 }
795 
796 // properties
797 PROP_REQ [] = {
798  { "Type", PROP_STR, { PROP_NO_VAL, "lin" },
799  PROP_RNG_STR2 ("lin", "log") },
800  { "Start", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
801  { "Stop", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE },
802  { "Points", PROP_INT, { 10, PROP_NO_STR }, PROP_MIN_VAL (2) },
803  PROP_NO_PROP };
804 PROP_OPT [] = {
805  { "IntegrationMethod", PROP_STR, { PROP_NO_VAL, "Trapezoidal" },
806  PROP_RNG_STR4 ("Euler", "Trapezoidal", "Gear", "AdamsMoulton") },
807  { "Order", PROP_INT, { 2, PROP_NO_STR }, PROP_RNGII (1, 6) },
808  { "InitialStep", PROP_REAL, { 1e-9, PROP_NO_STR }, PROP_POS_RANGE },
809  { "MinStep", PROP_REAL, { 1e-16, PROP_NO_STR }, PROP_POS_RANGE },
810  { "MaxStep", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
811  { "MaxIter", PROP_INT, { 150, PROP_NO_STR }, PROP_RNGII (2, 10000) },
812  { "abstol", PROP_REAL, { 1e-12, PROP_NO_STR }, PROP_RNG_X01I },
813  { "vntol", PROP_REAL, { 1e-6, PROP_NO_STR }, PROP_RNG_X01I },
814  { "reltol", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_RNG_X01I },
815  { "LTEabstol", PROP_REAL, { 1e-6, PROP_NO_STR }, PROP_RNG_X01I },
816  { "LTEreltol", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_RNG_X01I },
817  { "LTEfactor", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (1, 16) },
818  { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
819  { "Solver", PROP_STR, { PROP_NO_VAL, "CroutLU" }, PROP_RNG_SOL },
820  { "relaxTSR", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
821  { "initialDC", PROP_STR, { PROP_NO_VAL, "yes" }, PROP_RNG_YESNO },
822  PROP_NO_PROP };
823 struct define_t trsolver::anadef =