Qucs-core  0.0.19
dcsolver.cpp
Go to the documentation of this file.
00001 /*
00002  * dcsolver.cpp - DC solver class implementation
00003  *
00004  * Copyright (C) 2003-2008 Stefan Jahn <stefan@lkcc.org>
00005  *
00006  * This is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2, or (at your option)
00009  * any later version.
00010  *
00011  * This software is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this package; see the file COPYING.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  * $Id$
00022  *
00023  */
00024 
00025 #if HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 #include <stdio.h>
00030 
00031 #include "object.h"
00032 #include "complex.h"
00033 #include "circuit.h"
00034 #include "net.h"
00035 #include "netdefs.h"
00036 #include "analysis.h"
00037 #include "nasolver.h"
00038 #include "dcsolver.h"
00039 
00040 namespace qucs {
00041 
00042 // Constructor creates an unnamed instance of the dcsolver class.
00043 dcsolver::dcsolver () : nasolver<nr_double_t> () {
00044   saveOPs = 0;
00045   type = ANALYSIS_DC;
00046   setDescription ("DC");
00047 }
00048 
00049 // Constructor creates a named instance of the dcsolver class.
00050 dcsolver::dcsolver (char * n) : nasolver<nr_double_t> (n) {
00051   saveOPs = 0;
00052   type = ANALYSIS_DC;
00053   setDescription ("DC");
00054 }
00055 
00056 // Destructor deletes the dcsolver class object.
00057 dcsolver::~dcsolver () {
00058 }
00059 
00060 /* The copy constructor creates a new instance of the dcsolver class
00061    based on the given dcsolver object. */
00062 dcsolver::dcsolver (dcsolver & o) : nasolver<nr_double_t> (o) {
00063   saveOPs = o.saveOPs;
00064 }
00065 
00066 /* This is the DC netlist solver.  It prepares the circuit list and
00067    solves it then. */
00068 int dcsolver::solve (void) {
00069   // fetch simulation properties
00070   saveOPs |= !strcmp (getPropertyString ("saveOPs"), "yes") ? SAVE_OPS : 0;
00071   saveOPs |= !strcmp (getPropertyString ("saveAll"), "yes") ? SAVE_ALL : 0;
00072   const char * const solver = getPropertyString ("Solver");
00073 
00074   // initialize node voltages, first guess for non-linear circuits and
00075   // generate extra circuits if necessary
00076   init ();
00077   setCalculation ((calculate_func_t) &calc);
00078 
00079   // start the iterative solver
00080   solve_pre ();
00081 
00082   // choose a solver
00083   if (!strcmp (solver, "CroutLU"))
00084     eqnAlgo = ALGO_LU_DECOMPOSITION_CROUT;
00085   else if (!strcmp (solver, "DoolittleLU"))
00086     eqnAlgo = ALGO_LU_DECOMPOSITION_DOOLITTLE;
00087   else if (!strcmp (solver, "HouseholderQR"))
00088     eqnAlgo = ALGO_QR_DECOMPOSITION;
00089   else if (!strcmp (solver, "HouseholderLQ"))
00090     eqnAlgo = ALGO_QR_DECOMPOSITION_LS;
00091   else if (!strcmp (solver, "GolubSVD"))
00092     eqnAlgo = ALGO_SV_DECOMPOSITION;
00093 
00094   // local variables for the fallback thingies
00095   int retry = -1, error, fallback = 0, preferred;
00096   int helpers[] = {
00097     CONV_SourceStepping,
00098     CONV_GMinStepping,
00099     CONV_SteepestDescent,
00100     CONV_LineSearch,
00101     CONV_Attenuation,
00102     -1 };
00103 
00104   // is a certain convergence helper requested?
00105   const char * const helper = getPropertyString ("convHelper");
00106   convHelper = CONV_None;
00107   if (!strcmp (helper, "LineSearch")) {
00108     convHelper = CONV_LineSearch;
00109   } else if (!strcmp (helper, "SteepestDescent")) {
00110     convHelper = CONV_SteepestDescent;
00111   } else if (!strcmp (helper, "Attenuation")) {
00112     convHelper = CONV_Attenuation;
00113   } else if (!strcmp (helper, "gMinStepping")) {
00114     convHelper = CONV_GMinStepping;
00115   } else if (!strcmp (helper, "SourceStepping")) {
00116     convHelper = CONV_SourceStepping;
00117   }
00118   preferred = convHelper;
00119 
00120   if (!subnet->isNonLinear ()) {
00121     // Start the linear solver.
00122     convHelper = CONV_None;
00123     error = solve_linear ();
00124   }
00125   else do {
00126     // Run the DC solver once.
00127     try_running () {
00128       applyNodeset ();
00129       error = solve_nonlinear ();
00130 #if DEBUG
00131       if (!error) {
00132         logprint (LOG_STATUS,
00133                   "NOTIFY: %s: convergence reached after %d iterations\n",
00134                   getName (), iterations);
00135       }
00136 #endif /* DEBUG */
00137       if (!error) retry = -1;
00138     }
00139     // Appropriate exception handling.
00140     catch_exception () {
00141     case EXCEPTION_NO_CONVERGENCE:
00142       pop_exception ();
00143       if (preferred == helpers[fallback] && preferred) fallback++;
00144       convHelper = helpers[fallback++];
00145       if (convHelper != -1) {
00146         logprint (LOG_ERROR, "WARNING: %s: %s analysis failed, using fallback "
00147                   "#%d (%s)\n", getName (), getDescription ().c_str(), fallback,
00148                   getHelperDescription ());
00149         retry++;
00150         restart ();
00151       }
00152       else {
00153         retry = -1;
00154       }
00155       break;
00156     default:
00157       // Otherwise return.
00158       estack.print ();
00159       error++;
00160       break;
00161     }
00162   } while (retry != -1);
00163 
00164   // save results and cleanup the solver
00165   saveOperatingPoints ();
00166   saveResults ("V", "I", saveOPs);
00167 
00168   solve_post ();
00169   return 0;
00170 }
00171 
00172 /* Goes through the list of circuit objects and runs its calcDC()
00173    function. */
00174 void dcsolver::calc (dcsolver * self) {
00175   circuit * root = self->getNet()->getRoot ();
00176   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00177     c->calcDC ();
00178   }
00179 }
00180 
00181 /* Goes through the list of circuit objects and runs its initDC()
00182    function. */
00183 void dcsolver::init (void) {
00184   circuit * root = subnet->getRoot ();
00185   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00186     c->initDC ();
00187   }
00188 }
00189 
00190 /* Goes through the list of non-linear circuit objects and runs its
00191    restartDC() function. */
00192 void dcsolver::restart (void) {
00193   circuit * root = subnet->getRoot ();
00194   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00195     if (c->isNonLinear ()) c->restartDC ();
00196   }
00197 }
00198 
00199 /* Goes through the list of non-linear circuit objects and runs its
00200    saveOperatingPoints() function. */
00201 void dcsolver::saveOperatingPoints (void) {
00202   circuit * root = subnet->getRoot ();
00203   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00204     if (c->isNonLinear ()) c->saveOperatingPoints ();
00205   }
00206 }
00207 
00208 // properties
00209 PROP_REQ [] = {
00210   PROP_NO_PROP };
00211 PROP_OPT [] = {
00212   { "MaxIter", PROP_INT, { 150, PROP_NO_STR }, PROP_RNGII (2, 10000) },
00213   { "abstol", PROP_REAL, { 1e-12, PROP_NO_STR }, PROP_RNG_X01I },
00214   { "vntol", PROP_REAL, { 1e-6, PROP_NO_STR }, PROP_RNG_X01I },
00215   { "reltol", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_RNG_X01I },
00216   { "saveOPs", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
00217   { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
00218   { "saveAll", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
00219   { "convHelper", PROP_STR, { PROP_NO_VAL, "none" },
00220     PROP_RNG_STR6 ("none", "SourceStepping", "gMinStepping",
00221                    "LineSearch", "Attenuation", "SteepestDescent") },
00222   { "Solver", PROP_STR, { PROP_NO_VAL, "CroutLU" }, PROP_RNG_SOL },
00223   PROP_NO_PROP };
00224 struct define_t dcsolver::anadef =
00225   { "DC", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };
00226 
00227 } // namespace qucs