My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
net.cpp
Go to the documentation of this file.
1 /*
2  * net.cpp - net class implementation
3  *
4  * Copyright (C) 2003, 2004, 2005, 2006, 2007 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: net.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 <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 
34 #include "logging.h"
35 #include "complex.h"
36 #include "object.h"
37 #include "node.h"
38 #include "circuit.h"
39 #include "strlist.h"
40 #include "vector.h"
41 #include "dataset.h"
42 #include "net.h"
43 #include "tee.h"
44 #include "open.h"
45 #include "itrafo.h"
46 #include "ptrlist.h"
47 #include "analysis.h"
48 #include "nodelist.h"
49 #include "nodeset.h"
50 #include "equation.h"
51 #include "environment.h"
52 #include "component_id.h"
53 
54 // Constructor creates an unnamed instance of the net class.
55 net::net () : object () {
56  root = drop = NULL;
57  nPorts = nCircuits = nSources = 0;
58  insertedNodes = inserted = reduced = 0;
59  actions = new ptrlist<analysis> ();
60  orgacts = new ptrlist<analysis> ();
61  env = NULL;
62  nset = NULL;
63  srcFactor = 1;
64 }
65 
66 // Constructor creates a named instance of the net class.
67 net::net (const char * n) : object (n) {
68  root = drop = NULL;
69  nPorts = nCircuits = nSources = 0;
70  insertedNodes = inserted = reduced = 0;
71  actions = new ptrlist<analysis> ();
72  orgacts = new ptrlist<analysis> ();
73  env = NULL;
74  nset = NULL;
75  srcFactor = 1;
76 }
77 
78 // Destructor deletes the net class object.
80  circuit * n;
81  // delete each and every circuit
82  for (circuit * c = root; c != NULL; c = n) {
83  n = (circuit *) c->getNext ();
84  delete c;
85  }
86  // delete original actions
87  for (int i = 0; i < orgacts->length (); i++) delete orgacts->get (i);
88  delete orgacts;
89  // delete nodeset
90  delNodeset ();
91  delete actions;
92 }
93 
94 /* The copy constructor creates a new instance of the net class based
95  on the given net object. */
96 net::net (net & n) : object (n) {
97  root = drop = NULL;
98  nPorts = nCircuits = nSources = 0;
99  insertedNodes = inserted = reduced = 0;
100  actions = n.actions ? new ptrlist<analysis> (*n.actions) : NULL;
101  orgacts = new ptrlist<analysis> ();
102  env = n.env;
103  nset = NULL;
104  srcFactor = 1;
105 }
106 
107 /* This function prepends the given circuit to the list of registered
108  circuits. */
110 #if 0
111  assert (!containsCircuit (c));
112 #endif
113 
114  // chain circuit appropriately
115  if (root) root->setPrev (c);
116  c->setNext (root);
117  c->setPrev (NULL);
118  root = c;
119  nCircuits++;
120  c->setEnabled (1);
121  c->setNet (this);
122 
123  /* handle AC power sources as s-parameter ports if it is not part of
124  a subcircuit */
125  if (c->getType () == CIR_PAC && c->getSubcircuit () == NULL) {
126  nPorts++;
127  if (!c->getPort ()) c->setPort (c->getPropertyInteger ("Num"));
128  }
129  // handle DC voltage sources
130  if (c->getVoltageSources () > 0) {
131  if (c->getVoltageSource () < 0) c->setVoltageSource (nSources);
132  nSources += c->getVoltageSources ();
133  }
134 }
135 
136 /* The function removes the given circuit from the list of registered
137  circuits. */
138 void net::removeCircuit (circuit * c, int dropping) {
139 #if 0
140  assert (containsCircuit (c));
141 #endif
142 
143  // adjust the circuit chain appropriately
144  if (c == root) {
145  root = (circuit *) c->getNext ();
146  if (root) root->setPrev (NULL);
147  }
148  else {
149  if (c->getNext ()) c->getNext()->setPrev (c->getPrev ());
150  c->getPrev()->setNext (c->getNext ());
151  }
152  nCircuits--;
153  c->setEnabled (0);
154  c->setNet (NULL);
155  if (c->getPort ()) nPorts--;
156  if (c->getVoltageSource () >= 0) nSources -= c->getVoltageSources ();
157 
158  // shift the circuit object to the drop list
159  if (c->isOriginal ()) {
160  if (dropping) {
161  if (drop) drop->setPrev (c);
162  c->setNext (drop);
163  c->setPrev (NULL);
164  drop = c;
165  }
166  }
167  // really destroy the circuit object
168  else delete c;
169 }
170 
171 /* The function returns non-zero if the given circuit is already part
172  of the netlist. It returns zero if not. */
174  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
175  if (c == cand) return 1;
176  return 0;
177 }
178 
179 /* This function prepends the given analysis to the list of registered
180  analyses. */
182  orgacts->add (a);
183  actions->add (a);
184 }
185 
186 /* The function removes the given analysis from the list of registered
187  analyses. */
189  actions->del (a);
190 }
191 
192 /* The function returns the analysis associated with the netlist
193  object specified by the given instance name and returns NULL if
194  there is no such analysis. */
196  if (n == NULL) return NULL;
197  for (int i = 0; i < actions->length (); i++) {
198  analysis * a = actions->get (i);
199  if (!strcmp (a->getName (), n))
200  return a;
201  }
202  return NULL;
203 }
204 
205 /* The function returns the analysis associated with the netlist
206  object specified by the given type of analysis and returns NULL if
207  there is no such analysis. */
209  for (int i = 0; i < actions->length (); i++) {
210  analysis * a = actions->get (i);
211  if (a->getType () == type)
212  return a;
213  }
214  return NULL;
215 }
216 
217 /* Looks recursively for a type of analysis. */
218 int net::containsAnalysis (analysis * child, int type) {
219  ptrlist<analysis> * alist = child->getAnalysis ();
220  for (int i = 0; alist && i < alist->length (); i++) {
221  analysis * a = alist->get (i);
222  if (a->getType () == type)
223  return 1;
224  else if (a->getType () == ANALYSIS_SWEEP)
225  return containsAnalysis (a, type);
226  }
227  return 0;
228 }
229 
230 /* This function runs all registered analyses applied to the current
231  netlist. */
232 dataset * net::runAnalysis (int &err) {
233  dataset * out = new dataset ();
234  analysis * a;
235  int i;
236 
237  // apply some data to all analyses
238  for (i = 0; i < actions->length (); i++) {
239  a = actions->get (i);
240  a->setNet (this);
241  a->setData (out);
242  }
243 
244  // re-order analyses
245  orderAnalysis ();
246 
247  // initialize analyses
248  for (i = 0; i < actions->length (); i++) {
249  a = actions->get (i);
250  err |= a->initialize ();
251  }
252 
253  // solve the analyses
254  for (i = 0; i < actions->length (); i++) {
255  a = actions->get (i);
256  a->getEnv()->runSolver ();
257  err |= a->solve ();
258  }
259 
260  // cleanup analyses
261  for (i = 0; i < actions->length (); i++) {
262  a = actions->get (i);
263  err |= a->cleanup ();
264  }
265 
266  return out;
267 }
268 
269 /* The function returns the analysis with the second lowest order. If
270  there is no recursive sweep it returns NULL. */
272  analysis * parent = NULL;
273  for (int i = 0; i < actions->length (); i++) {
274  analysis * a = actions->get (i);
275  // parameter sweeps are potential parent sweeps
276  if (a->getType () == ANALYSIS_SWEEP) {
277  // find the appropriate sub analysis
278  analysis * child = getChildAnalysis (a);
279  if (child != NULL) {
280  // check if child is not another variable sweep
281  if (child->getType () != ANALYSIS_SWEEP) {
282  parent = a;
283  break;
284  }
285  // check if the child's child is still in the analysis list
286  else if (getChildAnalysis (child) == NULL) {
287  parent = a;
288  break;
289  }
290  }
291  }
292  }
293  return parent;
294 }
295 
296 /* The function reorders (prioritizes) the registered analysis to the
297  netlist object. In fact it chains the analyses to be executed in
298  a certain order. */
299 void net::orderAnalysis (void) {
300  analysis * parent, * child, * a;
302  int i, dcApplied = 0;
303  do {
304  // get second order sweep
305  if ((parent = findSecondOrder ()) != NULL) {
306  child = getChildAnalysis (parent);
307  removeAnalysis (child);
308  // apply sub-analysis to each parent analysis if any
309  for (i = 0; i < actions->length (); i++) {
310  a = actions->get (i);
311  char * cn = getChild (a);
312  if (cn != NULL && !strcmp (cn, child->getName ())) {
313  a->addAnalysis (child);
314  // apply DC analysis if necessary
315  if (child->getType () != ANALYSIS_DC &&
316  child->getType () != ANALYSIS_SWEEP && dc != NULL) {
317  if (!dcApplied) removeAnalysis (dc);
318  a->addAnalysis (dc);
319  dcApplied++;
320  }
321  }
322  }
323  // sort the sub-analysis of each parent
324  for (i = 0; i < actions->length (); i++) {
325  a = actions->get (i);
326  sortChildAnalyses (a);
327  }
328  }
329  } while (parent != NULL);
330 
331  // sort the parent analyses
332  parent = new analysis ();
333  parent->setAnalysis (actions);
334  sortChildAnalyses (parent);
335  actions = new ptrlist<analysis> (*(parent->getAnalysis ()));
336  delete parent;
337 }
338 
339 // This function sorts the analyses of the given parent analysis.
341  ptrlist<analysis> * alist = parent->getAnalysis ();
342  for (int i = 0; alist && i < alist->length (); i++) {
343  analysis * a = alist->get (i);
344  if (a->getType () == ANALYSIS_DC
345  || containsAnalysis (a, ANALYSIS_DC)) {
346  parent->delAnalysis (a);
347  parent->addAnalysis (a);
348  }
349  }
350 }
351 
352 // Returns the instance name of the given parents child analysis.
353 char * net::getChild (analysis * parent) {
354  char * child = NULL;
355  if (parent != NULL && parent->getType () == ANALYSIS_SWEEP)
356  child = parent->getPropertyString ("Sim");
357  return child;
358 }
359 
360 // Returns the child analysis of the given parent if possible.
362  return findAnalysis (getChild (parent));
363 }
364 
365 // Returns the last order sweep being not an parameter sweep.
367  ptrlist<analysis> * alist = a->getAnalysis ();
368  analysis * child = alist ? alist->get (0) : NULL;
369  if (child != NULL && child->getType () == ANALYSIS_SWEEP) {
370  return findLastOrder (child);
371  }
372  return child ? child : a;
373 }
374 
375 // Returns the last order sweep being not an parameter sweep.
377  ptrlist<analysis> * alist = a->getAnalysis ();
378  analysis * child = alist ? alist->get (0) : NULL;
379  if (child != NULL && child->getType () == ANALYSIS_SWEEP) {
380  return findLastOrderChildren (child);
381  }
382  return alist;
383 }
384 
385 /* The function re-shifts all circuits in the drop list to the actual
386  list of circuit objects. */
388  circuit * n;
389  for (circuit * c = drop; c != NULL; c = n) {
390  n = (circuit *) c->getNext ();
391  if (nodes) nodes->insert (c);
392  insertCircuit (c);
393  }
394  drop = NULL;
395 }
396 
397 /* This function deletes all unnecessary circuits in the list of
398  registered circuit objects. */
400  circuit * n;
401  for (circuit * c = root; c != NULL; c = n) {
402  n = (circuit *) c->getNext ();
403  if (!c->isOriginal ()) {
404  if (nodes) nodes->remove (c);
405  removeCircuit (c);
406  }
407  }
408 }
409 
410 /* Returns the first node in the list of real circuit objects
411  connected to the given node. If there is no such node (unconnected
412  node) the function returns NULL. */
414 
415  char * _name = n->getName ();
416  node * _node;
417 
418  // through the list of circuit objects
419  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
420  // skip signal circuits
421  if (c->getPort ()) continue;
422  // through the list of nodes in a circuit
423  for (int i = 0; i < c->getSize (); i++) {
424  _node = c->getNode (i);
425  if (!strcmp (_node->getName (), _name)) {
426  if (_node != n) {
427  return _node;
428  }
429  }
430  }
431  }
432  return NULL;
433 }
434 
435 /* Returns the first node in the list of circuit objects (including
436  signals) connected to the given node. If there is no such node
437  (unconnected node) the function returns NULL. */
439 
440  char * _name = n->getName ();
441  node * _node;
442 
443  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
444  for (int i = 0; i < c->getSize (); i++) {
445  _node = c->getNode (i);
446  if (!strcmp (_node->getName (), _name)) {
447  if (_node != n) {
448  return _node;
449  }
450  }
451  }
452  }
453  return NULL;
454 }
455 
456 // Rename the given circuit and mark it as being a reduced one.
458  char n[32];
459  sprintf (n, "reduced%d", reduced++);
460  c->setName (n);
461 }
462 
463 /* Rename the given circuit and mark it as being a inserted one and
464  remember when it was inserted. */
466  char n[32];
467  sprintf (n, "inserted%d", inserted);
468  c->setName (n);
469  c->setInserted (inserted);
470  inserted++;
471 }
472 
473 // Rename the given node and mark it as being a inserted one.
475  char n[32];
476  sprintf (n, "inode%d", insertedNodes++);
477  c->setName (n);
478 }
479 
480 /* This helper function checks whether the circuit chain of the
481  netlist is properly working. It returns the number of errors or
482  zero if there are no errors. */
484  int error = 0;
485  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
486  if (c->getPrev ())
487  if (c->getPrev()->getNext () != c) {
488  error++;
489  logprint (LOG_ERROR, "ERROR: prev->next != circuit '%s'\n",
490  c->getName ());
491  }
492  if (c->getNext ())
493  if (c->getNext()->getPrev () != c) {
494  error++;
495  logprint (LOG_ERROR, "ERROR: next->prev != circuit '%s'\n",
496  c->getName ());
497  }
498  }
499  return error;
500 }
501 
502 /* This function counts the number of signals (ports) within the list
503  of registerd circuits. */
504 int net::countPorts (void) {
505  int count = 0;
506  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
507  if (c->getPort ()) count++;
508  }
509  return count;
510 }
511 
512 /* This function counts the number of circuits within the list of
513  registered circuits. */
514 int net::countNodes (void) {
515  int count = 0;
516  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
517  if (!c->getPort ()) count += c->getSize ();
518  }
519  return count;
520 }
521 
522 /* The function returns the number of non-linear circuits within the
523  list of registered circuits. */
524 int net::isNonLinear (void) {
525  int count = 0;
526  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
527  if (c->isNonLinear ()) count++;
528  }
529  return count;
530 }
531 
532 /* The function adds the given nodeset object to the netlist's nodeset
533  list. */
535  n->setNext (nset);
536  nset = n;
537 }
538 
539 /* The following function deletes all the nodeset list of the netlist
540  object. Called from the destructor. */
541 void net::delNodeset (void) {
542  nodeset * next;
543  for (nodeset * n = nset; n != NULL; n = next) {
544  next = n->getNext ();
545  delete n;
546  }
547  nset = NULL;
548 }
549 
550 #if DEBUG
551 // DEBUG function: Lists the netlist.
552 void net::list (void) {
553  logprint (LOG_STATUS, "DEBUG: netlist `%s' (%d circuits, "
554  "%d ports, %d nodes)\n", getName (), countPorts (),
555  countPorts (), countNodes ());
556  // go through circuit list
557  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
558  // list each circuit
559  logprint (LOG_STATUS, " %s[", c->getName ());
560  for (int i = 0; i < c->getSize (); i++) {
561  logprint (LOG_STATUS, "%s-%d",
562  c->getNode(i)->getName (), c->getNode(i)->getNode ());
563  if (i < c->getSize () - 1)
564  logprint (LOG_STATUS, ",");
565  }
566  logprint (LOG_STATUS, "] { %s }\n", c->propertyList ());
567  }
568 }
569 #endif /* DEBUG */