Qucs-core
0.0.19
|
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