Qucs-core  0.0.19
net.cpp
Go to the documentation of this file.
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