Qucs-core
0.0.19
|
00001 /* 00002 * net.cpp - net class implementation 00003 * 00004 * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 #include <stdlib.h> 00031 #include <string.h> 00032 #include <assert.h> 00033 00034 #include "logging.h" 00035 #include "complex.h" 00036 #include "object.h" 00037 #include "node.h" 00038 #include "circuit.h" 00039 #include "strlist.h" 00040 #include "vector.h" 00041 #include "dataset.h" 00042 #include "net.h" 00043 #include "tee.h" 00044 #include "open.h" 00045 #include "itrafo.h" 00046 #include "ptrlist.h" 00047 #include "analysis.h" 00048 #include "nodelist.h" 00049 #include "nodeset.h" 00050 #include "equation.h" 00051 #include "environment.h" 00052 #include "component_id.h" 00053 00054 namespace qucs { 00055 00056 // Constructor creates an unnamed instance of the net class. 00057 net::net () : object () { 00058 root = drop = NULL; 00059 nPorts = nCircuits = nSources = 0; 00060 insertedNodes = inserted = reduced = 0; 00061 actions = new ptrlist<analysis> (); 00062 orgacts = new ptrlist<analysis> (); 00063 env = NULL; 00064 nset = NULL; 00065 srcFactor = 1; 00066 } 00067 00068 // Constructor creates a named instance of the net class. 00069 net::net (const std::string &n) : object (n) { 00070 root = drop = NULL; 00071 nPorts = nCircuits = nSources = 0; 00072 insertedNodes = inserted = reduced = 0; 00073 actions = new ptrlist<analysis> (); 00074 orgacts = new ptrlist<analysis> (); 00075 env = NULL; 00076 nset = NULL; 00077 srcFactor = 1; 00078 } 00079 00080 // Destructor deletes the net class object. 00081 net::~net () { 00082 circuit * n; 00083 // delete each and every circuit 00084 for (circuit * c = root; c != NULL; c = n) { 00085 n = (circuit *) c->getNext (); 00086 delete c; 00087 } 00088 // delete original actions 00089 for(auto * element : *orgacts) { 00090 delete element; 00091 element = nullptr; 00092 } 00093 00094 delete orgacts; 00095 // delete nodeset 00096 delNodeset (); 00097 delete actions; 00098 } 00099 00100 /* The copy constructor creates a new instance of the net class based 00101 on the given net object. */ 00102 net::net (net & n) : object (n) { 00103 root = drop = NULL; 00104 nPorts = nCircuits = nSources = 0; 00105 insertedNodes = inserted = reduced = 0; 00106 actions = n.actions ? new ptrlist<analysis> (*n.actions) : NULL; 00107 orgacts = new ptrlist<analysis> (); 00108 env = n.env; 00109 nset = NULL; 00110 srcFactor = 1; 00111 } 00112 00113 /* This function prepends the given circuit to the list of registered 00114 circuits. */ 00115 void net::insertCircuit (circuit * c) { 00116 #if 0 00117 assert (!containsCircuit (c)); 00118 #endif 00119 00120 // chain circuit appropriately 00121 if (root) root->setPrev (c); 00122 c->setNext (root); 00123 c->setPrev (NULL); 00124 root = c; 00125 nCircuits++; 00126 c->setEnabled (1); 00127 c->setNet (this); 00128 00129 /* handle AC power sources as s-parameter ports if it is not part of 00130 a subcircuit */ 00131 if (c->getType () == CIR_PAC && c->getSubcircuit ().empty()) { 00132 nPorts++; 00133 if (!c->getPort ()) c->setPort (c->getPropertyInteger ("Num")); 00134 } 00135 // handle DC voltage sources 00136 if (c->getVoltageSources () > 0) { 00137 if (c->getVoltageSource () < 0) c->setVoltageSource (nSources); 00138 nSources += c->getVoltageSources (); 00139 } 00140 } 00141 00142 /* The function removes the given circuit from the list of registered 00143 circuits. */ 00144 void net::removeCircuit (circuit * c, int dropping) { 00145 #if 0 00146 assert (containsCircuit (c)); 00147 #endif 00148 00149 // adjust the circuit chain appropriately 00150 if (c == root) { 00151 root = (circuit *) c->getNext (); 00152 if (root) root->setPrev (NULL); 00153 } 00154 else { 00155 if (c->getNext ()) c->getNext()->setPrev (c->getPrev ()); 00156 c->getPrev()->setNext (c->getNext ()); 00157 } 00158 nCircuits--; 00159 c->setEnabled (0); 00160 c->setNet (NULL); 00161 if (c->getPort ()) nPorts--; 00162 if (c->getVoltageSource () >= 0) nSources -= c->getVoltageSources (); 00163 00164 // shift the circuit object to the drop list 00165 if (c->isOriginal ()) { 00166 if (dropping) { 00167 if (drop) drop->setPrev (c); 00168 c->setNext (drop); 00169 c->setPrev (NULL); 00170 drop = c; 00171 } 00172 } 00173 // really destroy the circuit object 00174 else delete c; 00175 } 00176 00177 /* The function returns non-zero if the given circuit is already part 00178 of the netlist. It returns zero if not. */ 00179 int net::containsCircuit (circuit * cand) { 00180 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) 00181 if (c == cand) return 1; 00182 return 0; 00183 } 00184 00185 /* This function prepends the given analysis to the list of registered 00186 analyses. */ 00187 void net::insertAnalysis (analysis * a) { 00188 orgacts->push_front (a); 00189 actions->push_front (a); 00190 } 00191 00192 /* The function removes the given analysis from the list of registered 00193 analyses. */ 00194 void net::removeAnalysis (analysis * a) { 00195 actions->remove(a); 00196 } 00197 00198 /* The function returns the analysis associated with the netlist 00199 object specified by the given instance name and returns NULL if 00200 there is no such analysis. */ 00201 analysis * net::findAnalysis (const std::string &n) const { 00202 for (auto *a : *actions) { 00203 if (a->getName ()== n) 00204 return a; 00205 } 00206 return NULL; 00207 } 00208 00209 /* The function returns the analysis associated with the netlist 00210 object specified by the given type of analysis and returns NULL if 00211 there is no such analysis. */ 00212 analysis * net::findAnalysis (int type) { 00213 for (auto *a: *actions) { 00214 if (a->getType () == type) 00215 return a; 00216 } 00217 return NULL; 00218 } 00219 00220 /* Looks recursively for a type of analysis. */ 00221 int net::containsAnalysis (analysis * child, int type) { 00222 ptrlist<analysis> * alist = child->getAnalysis (); 00223 if(alist != nullptr) { 00224 for (auto *a : *alist) { 00225 if (a->getType () == type) 00226 return 1; 00227 else if (a->getType () == ANALYSIS_SWEEP) 00228 return containsAnalysis (a, type); 00229 } 00230 } 00231 return 0; 00232 } 00233 00234 /* This function runs all registered analyses applied to the current 00235 netlist, except for external analysis types. */ 00236 dataset * net::runAnalysis (int &err) { 00237 dataset * out = new dataset (); 00238 00239 // apply some data to all analyses 00240 for (auto *a : *actions) { 00241 if (!a->isExternal ()) 00242 { 00243 a->setNet (this); 00244 a->setData (out); 00245 } 00246 } 00247 00248 // re-order analyses 00249 orderAnalysis (); 00250 00251 // initialize analyses 00252 for (auto *a: * actions) { 00253 if (!a->isExternal ()) 00254 { 00255 err |= a->initialize (); 00256 } 00257 } 00258 00259 // solve the analyses 00260 for (auto *a: * actions) { 00261 if (!a->isExternal ()) 00262 { 00263 a->getEnv()->runSolver (); 00264 err |= a->solve (); 00265 } 00266 } 00267 00268 // cleanup analyses 00269 for (auto *a: *actions) { 00270 if (!a->isExternal ()) 00271 { 00272 err |= a->cleanup (); 00273 } 00274 } 00275 00276 return out; 00277 } 00278 00279 /* The function returns the analysis with the second lowest order. If 00280 there is no recursive sweep it returns NULL. */ 00281 analysis * net::findSecondOrder (void) { 00282 analysis * parent = NULL; 00283 for (auto *a : *actions) { 00284 // parameter sweeps are potential parent sweeps 00285 if (a->getType () == ANALYSIS_SWEEP) { 00286 // find the appropriate sub analysis 00287 analysis * child = getChildAnalysis (a); 00288 if (child != NULL) { 00289 // check if child is not another variable sweep 00290 if (child->getType () != ANALYSIS_SWEEP) { 00291 parent = a; 00292 break; 00293 } 00294 // check if the child's child is still in the analysis list 00295 else if (getChildAnalysis (child) == NULL) { 00296 parent = a; 00297 break; 00298 } 00299 } 00300 } 00301 } 00302 return parent; 00303 } 00304 00305 /* The function reorders (prioritizes) the registered analysis to the 00306 netlist object. In fact it chains the analyses to be executed in 00307 a certain order. */ 00308 void net::orderAnalysis (void) { 00309 analysis * parent, * child; 00310 analysis * dc = findAnalysis (ANALYSIS_DC); 00311 int dcApplied = 0; 00312 do { 00313 // get second order sweep 00314 if ((parent = findSecondOrder ()) != NULL) { 00315 child = getChildAnalysis (parent); 00316 removeAnalysis (child); 00317 // apply sub-analysis to each parent analysis if any 00318 if (actions != nullptr) { 00319 for (auto *a: *actions) { 00320 const char * cn = getChild (a); 00321 if (cn != NULL && !strcmp (cn, child->getName ())) { 00322 a->addAnalysis (child); 00323 // apply DC analysis if necessary 00324 if (child->getType () != ANALYSIS_DC && 00325 child->getType () != ANALYSIS_SWEEP && dc != NULL) { 00326 if (!dcApplied) 00327 removeAnalysis (dc); 00328 a->addAnalysis (dc); 00329 dcApplied++; 00330 } 00331 } 00332 } 00333 } 00334 // sort the sub-analysis of each parent 00335 for (auto *a: *actions) { 00336 sortChildAnalyses (a); 00337 } 00338 } 00339 } while (parent != NULL); 00340 00341 // sort the parent analyses 00342 parent = new analysis (); 00343 parent->setAnalysis (actions); 00344 sortChildAnalyses (parent); 00345 actions = new ptrlist<analysis> (*(parent->getAnalysis ())); 00346 delete parent; 00347 } 00348 00349 // This function sorts the analyses of the given parent analysis. 00350 void net::sortChildAnalyses (analysis * parent) { 00351 ptrlist<analysis> * alist = parent->getAnalysis (); 00352 if (alist != nullptr) { 00353 for (auto *a: *alist) { 00354 if (a->getType () == ANALYSIS_DC 00355 || containsAnalysis (a, ANALYSIS_DC)) { 00356 parent->delAnalysis (a); 00357 parent->addAnalysis (a); 00358 } 00359 } 00360 } 00361 } 00362 00363 // Returns the instance name of the given parents child analysis. 00364 const char * net::getChild (analysis * parent) const { 00365 const char * child = NULL; 00366 if (parent != NULL && parent->getType () == ANALYSIS_SWEEP) 00367 child = parent->getPropertyString ("Sim"); 00368 return child; 00369 } 00370 00371 // Returns the child analysis of the given parent if possible. 00372 analysis * net::getChildAnalysis (analysis * parent) { 00373 return findAnalysis (getChild (parent)); 00374 } 00375 00376 // Returns the last order sweep being not an parameter sweep. 00377 analysis * net::findLastOrder (analysis * a) { 00378 ptrlist<analysis> * alist = a->getAnalysis (); 00379 analysis * child = alist ? alist->front() : NULL; 00380 if (child != NULL && child->getType () == ANALYSIS_SWEEP) { 00381 return findLastOrder (child); 00382 } 00383 return child ? child : a; 00384 } 00385 00386 // Returns the last order sweep being not an parameter sweep. 00387 ptrlist<analysis> * net::findLastOrderChildren (analysis * a) { 00388 ptrlist<analysis> * alist = a->getAnalysis (); 00389 analysis * child = alist ? alist->front() : NULL; 00390 if (child != NULL && child->getType () == ANALYSIS_SWEEP) { 00391 return findLastOrderChildren (child); 00392 } 00393 return alist; 00394 } 00395 00396 /* The function re-shifts all circuits in the drop list to the actual 00397 list of circuit objects. */ 00398 void net::getDroppedCircuits (nodelist * nodes) { 00399 circuit * n; 00400 for (circuit * c = drop; c != NULL; c = n) { 00401 n = (circuit *) c->getNext (); 00402 if (nodes) nodes->insert (c); 00403 insertCircuit (c); 00404 } 00405 drop = NULL; 00406 } 00407 00408 /* This function deletes all unnecessary circuits in the list of 00409 registered circuit objects. */ 00410 void net::deleteUnusedCircuits (nodelist * nodes) { 00411 circuit * n; 00412 for (circuit * c = root; c != NULL; c = n) { 00413 n = (circuit *) c->getNext (); 00414 if (!c->isOriginal ()) { 00415 if (nodes) nodes->remove (c); 00416 removeCircuit (c); 00417 } 00418 } 00419 } 00420 00421 /* Returns the first node in the list of real circuit objects 00422 connected to the given node. If there is no such node (unconnected 00423 node) the function returns NULL. */ 00424 node * net::findConnectedCircuitNode (node * n) { 00425 00426 const char * _name = n->getName (); 00427 node * _node; 00428 00429 // through the list of circuit objects 00430 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00431 // skip signal circuits 00432 if (c->getPort ()) continue; 00433 // through the list of nodes in a circuit 00434 for (int i = 0; i < c->getSize (); i++) { 00435 _node = c->getNode (i); 00436 if (!strcmp (_node->getName (), _name)) { 00437 if (_node != n) { 00438 return _node; 00439 } 00440 } 00441 } 00442 } 00443 return NULL; 00444 } 00445 00446 /* Returns the first node in the list of circuit objects (including 00447 signals) connected to the given node. If there is no such node 00448 (unconnected node) the function returns NULL. */ 00449 node * net::findConnectedNode (node * n) { 00450 00451 const char * _name = n->getName (); 00452 node * _node; 00453 00454 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00455 for (int i = 0; i < c->getSize (); i++) { 00456 _node = c->getNode (i); 00457 if (!strcmp (_node->getName (), _name)) { 00458 if (_node != n) { 00459 return _node; 00460 } 00461 } 00462 } 00463 } 00464 return NULL; 00465 } 00466 00467 // Rename the given circuit and mark it as being a reduced one. 00468 void net::reducedCircuit (circuit * c) { 00469 char n[32]; 00470 sprintf (n, "reduced%d", reduced++); 00471 c->setName (n); 00472 } 00473 00474 /* Rename the given circuit and mark it as being a inserted one and 00475 remember when it was inserted. */ 00476 void net::insertedCircuit (circuit * c) { 00477 char n[32]; 00478 sprintf (n, "inserted%d", inserted); 00479 c->setName (n); 00480 c->setInserted (inserted); 00481 inserted++; 00482 } 00483 00484 // Rename the given node and mark it as being a inserted one. 00485 void net::insertedNode (node * c) { 00486 char n[32]; 00487 sprintf (n, "inode%d", insertedNodes++); 00488 c->setName (n); 00489 } 00490 00491 /* This helper function checks whether the circuit chain of the 00492 netlist is properly working. It returns the number of errors or 00493 zero if there are no errors. */ 00494 int net::checkCircuitChain (void) { 00495 int error = 0; 00496 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00497 if (c->getPrev ()) 00498 if (c->getPrev()->getNext () != c) { 00499 error++; 00500 logprint (LOG_ERROR, "ERROR: prev->next != circuit '%s'\n", 00501 c->getName ()); 00502 } 00503 if (c->getNext ()) 00504 if (c->getNext()->getPrev () != c) { 00505 error++; 00506 logprint (LOG_ERROR, "ERROR: next->prev != circuit '%s'\n", 00507 c->getName ()); 00508 } 00509 } 00510 return error; 00511 } 00512 00513 /* This function counts the number of signals (ports) within the list 00514 of registerd circuits. */ 00515 int net::countPorts (void) { 00516 int count = 0; 00517 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00518 if (c->getPort ()) count++; 00519 } 00520 return count; 00521 } 00522 00523 /* This function counts the number of circuits within the list of 00524 registered circuits. */ 00525 int net::countNodes (void) { 00526 int count = 0; 00527 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00528 if (!c->getPort ()) count += c->getSize (); 00529 } 00530 return count; 00531 } 00532 00533 /* The function returns the number of non-linear circuits within the 00534 list of registered circuits. */ 00535 int net::isNonLinear (void) { 00536 int count = 0; 00537 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00538 if (c->isNonLinear ()) count++; 00539 } 00540 return count; 00541 } 00542 00543 /* The function adds the given nodeset object to the netlist's nodeset 00544 list. */ 00545 void net::addNodeset (nodeset * n) { 00546 n->setNext (nset); 00547 nset = n; 00548 } 00549 00550 /* The following function deletes all the nodeset list of the netlist 00551 object. Called from the destructor. */ 00552 void net::delNodeset (void) { 00553 nodeset * next; 00554 for (nodeset * n = nset; n != NULL; n = next) { 00555 next = n->getNext (); 00556 delete n; 00557 } 00558 nset = NULL; 00559 } 00560 00561 00562 void net::setActionNetAll(net * subnet) 00563 { 00564 for (auto *a : *(this->actions)) 00565 a->setNet(subnet); 00566 } 00567 00568 00569 #if DEBUG 00570 // DEBUG function: Lists the netlist. 00571 void net::list (void) { 00572 logprint (LOG_STATUS, "DEBUG: netlist `%s' (%d circuits, " 00573 "%d ports, %d nodes)\n", getName (), countPorts (), 00574 countPorts (), countNodes ()); 00575 // go through circuit list 00576 for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { 00577 // list each circuit 00578 logprint (LOG_STATUS, " %s[", c->getName ()); 00579 for (int i = 0; i < c->getSize (); i++) { 00580 logprint (LOG_STATUS, "%s-%d", 00581 c->getNode(i)->getName (), c->getNode(i)->getNode ()); 00582 if (i < c->getSize () - 1) 00583 logprint (LOG_STATUS, ","); 00584 } 00585 logprint (LOG_STATUS, "] { %s }\n", c->propertyList ()); 00586 } 00587 } 00588 #endif /* DEBUG */ 00589 00590 } // namespace qucs