Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

circuit.cc

Go to the documentation of this file.
00001 // circuit.cc
00002 // SuperMix version 1.0  C++ source file
00003 //
00004 // Copyright (c) 1999 California Institute of Technology.
00005 // All rights reserved.
00006 //
00007 // Redistribution and use in source and binary forms for noncommercial
00008 // purposes are permitted provided that the above copyright notice and
00009 // this paragraph are duplicated in all such forms and that any
00010 // documentation and other materials related to such distribution and
00011 // use acknowledge that the software was developed by California
00012 // Institute of Technology. Redistribution and/or use in source or
00013 // binary forms is not permitted for any commercial purpose. Use of
00014 // this software does not include a permitted use of the Institute's
00015 // name or trademark for any purpose.
00016 //
00017 // DISCLAIMER:
00018 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT
00019 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
00020 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET
00021 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
00022 // LICENSED PRODUCT, HOWEVER USED.  IN NO EVENT SHALL CALTECH/JPL BE
00023 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO
00024 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC
00025 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF
00026 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN
00027 // FACT SHALL KNOW OF THE POSSIBILITY.  THE USER BEARS ALL RISK
00028 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED
00029 // MATERIALS.
00030 //
00031 // Change history:
00032 // 2/24/00:  Added initialization of cascade::last to constructor
00033 // 11/16/99: Changes to support new noise calculations 
00034 // 10/29/99: Added better normalizing impedance handling.
00035 // 11/11/98: Changed table access to new syntax
00036 // 9/17/98:  added build_tree, etc. for huge speed increase.
00037 // 8/21/98:  added class cascade
00038 // 8/19/98:  added check for connecting a port to itself;
00039 //           added a local temperature Temp
00040 // 7/8/98:   added checks for nport indexing mode and size
00041 // 7/3/98:   added code to construct purely block-diagonal
00042 //           circuits, using new connection constructor
00043 // 6/26/98:  modified by FR for new sdata::size()
00044 // 12/29/97: modified by FR for new sdata (with znorm)
00045 // 12/19/97: modified by FR for matmath classes
00046 
00047 #include "circuit.h"
00048 #include "error.h"
00049 
00050 
00051 //**************************************************************
00052 // construction, assignment, and destruction
00053 
00054 circuit::circuit() : nport(0), tree_is_built(false), Temp(&T)
00055 { }
00056 
00057 
00058 circuit::circuit(const circuit & c) : nport(c), tree_is_built(false), Temp(c.Temp)
00059 {
00060   devset = c.devset;
00061   constack = c.constack;
00062   labels = c.labels;
00063 }
00064 
00065 
00066 circuit & circuit::operator=(const circuit & c)
00067 {
00068   // Beware of self assignment: c = c
00069   if(this != &c)
00070   {
00071     Temp = c.Temp;
00072     devset = c.devset;
00073     constack = c.constack;
00074     labels = c.labels;
00075     tree_is_built = false;
00076   }
00077   return *this;
00078 }
00079 
00080 
00081 circuit::~circuit()
00082 {
00083   while(!del_stack.empty())
00084   {
00085     delete del_stack.top();
00086     del_stack.pop();
00087   }
00088 }
00089 
00090 
00091 //**************************************************************
00092 // managing the data structures
00093 
00094 void circuit::connect(nport & dev1, int index1, nport & dev2, int index2)
00095 {
00096   port port1, port2;
00097   portArray p(2);
00098 
00099   // Make sure build_tree gets called to include this connection in the tree.
00100   tree_is_built = false;
00101 
00102   // Make sure port indices are valid.  If not, exit.
00103   if(dev1.size() == 0 || dev2.size() == 0)
00104     error::fatal("Can't connect an nport which doesn't know its size in circuit.");
00105   if(dev1.mode() != Index_1 || dev2.mode() != Index_1)
00106     error::fatal("Can only connect nports with mode()==Index_1 in circuit.");
00107   if((index1 < 1) || (index2 < 1) || (index1 > dev1.size()) || (index2 > dev2.size()))
00108     error::fatal("Illegal port index at circuit::connect.");
00109 
00110   port1 = port(dev1.id, index1);
00111   port2 = port(dev2.id, index2);
00112 
00113   // Make sure we're not connecting a port to itself
00114   if (port1 == port2)
00115     error::fatal("Can't connect a port to itself in circuit.");
00116 
00117   // Make sure neither port is already in connection list.
00118   if(constack.isPresent(port1) || constack.isPresent(port2))
00119     error::fatal("Can't connect one port in two places in circuit::connect.");
00120 
00121   // Make sure neither port is already in label list.
00122   if(labels.isPresent(port1) || labels.isPresent(port2))
00123     error::fatal("Can't connect one port in two places in circuit::connect.");
00124 
00125   // Create 2-element port array for adding to connection stack.
00126   p.set(1, port1);
00127   p.set(2, port2);
00128 
00129   // Add 2-element port array to the connection stack.
00130   constack.push(p);
00131 
00132   // Add the devices to the device set. The set makes sure they are only added once.
00133   devset.add(&dev1);
00134   devset.add(&dev2);
00135 }
00136 
00137 
00138 int circuit::add_port(nport & dev, int index)
00139 {
00140   // Make sure build_tree gets called to include this connection in the tree.
00141   tree_is_built = false;
00142 
00143   // Make sure port index is valid.  If not, exit.
00144   if(dev.size() == 0)
00145     error::fatal("Can't add an nport which doesn't know its size in circuit.");
00146   if(dev.mode() != Index_1)
00147     error::fatal("Can only add nports with mode()==Index_1 in circuit.");
00148   if((index < 1) || (index > dev.size()))
00149     error::fatal("Illegal port index at circuit::add_port.");
00150 
00151   port p(dev.id, index);
00152 
00153   // Make sure port isn't used in connection list.
00154   if(constack.isPresent(p))
00155     error::fatal("Port is already used in connection list at circuit::add_port.");
00156 
00157   // Make sure port isn't already in label list.
00158   if(labels.isPresent(p))
00159     error::fatal("Port is already used in label list at circuit::add_port.");
00160 
00161   devset.add(&dev);
00162   return(labels.add(p));
00163 }
00164 
00165 
00166 void circuit::build_tree()
00167 {
00168   nportSet devset_copy(devset);
00169   portStack constack_copy(constack);
00170   tmpList tmp_devs;
00171   nport *dev1;
00172   nport *dev2;
00173   int index1;
00174   int index2;
00175   nport *tmp1;
00176   nport *tmp2;
00177   connection *tmp3;
00178 
00179   portArray p;
00180 
00181   // Make sure the stack of temporary connections is empty.
00182   while(!del_stack.empty())
00183   {
00184     delete del_stack.top();
00185     del_stack.pop();
00186   }
00187 
00188   // Pop pairs of ports off connection stack until everything is connected.
00189   while(!constack_copy.isEmpty())
00190   {
00191     // Get a pair of ports to connect
00192     p = constack_copy.pop();
00193 
00194     // Get the first device
00195     dev1 = devset_copy.pop(p.get(1).id);
00196     if(dev1 == 0)       // Keep looking.
00197     {
00198       dev1 = tmp_devs.pop(p.get(1));
00199       if(dev1 == 0)
00200         error::fatal("Device not found in circuit::build_tree.");
00201     }
00202     index1 = dev1->get_port(p.get(1));
00203 
00204 
00205     // Get the second device
00206     dev2 = devset_copy.pop(p.get(2).id);
00207     if(dev2 == 0)       // Keep looking.
00208     {
00209       dev2 = tmp_devs.pop(p.get(2));
00210     }
00211 
00212     // Perform the connection
00213     if(dev2 == 0)       // Intra-connection
00214     {
00215       index2 = dev1->get_port(p.get(2));
00216       tmp1 = new connection(*dev1, index1, index2);
00217       del_stack.push((connection *)tmp1);
00218     }
00219     else        // Inter-connection
00220     {
00221       index2 = dev2->get_port(p.get(2));
00222       tmp1 = new connection(*dev1, index1, *dev2, index2);
00223       del_stack.push((connection *)tmp1);
00224     }
00225 
00226     // Stick the temporary device on the temporary device list.
00227     tmp_devs.add((connection *)tmp1);
00228   }
00229 
00230   // Now look for unconnected devices which are block-diagonal components.
00231   // Connect them in pairs.
00232   while(devset_copy.len() > 1)
00233   {
00234     // they must be added using connection, since circuit will delete them
00235     tmp1 = devset_copy.pop();
00236     tmp2 = devset_copy.pop();
00237     tmp3 = new connection(*tmp1, *tmp2);
00238     del_stack.push(tmp3);
00239     tmp_devs.add(tmp3);
00240   }
00241 
00242   // There could still be a device left.  If so, get it.  We can tell
00243   // we have one later if tmp1 is non-zero.
00244   tmp1 = NULL;
00245   if(devset_copy.len() > 0)
00246   {
00247     tmp1 = devset_copy.pop();
00248   }
00249 
00250   // By now, if there are any devices left in devset_copy, I've made a mistake.
00251   if(devset_copy.len() > 0)
00252   {
00253     error::fatal("Extra devices left on devset_copy in circuit::build_tree!");
00254   }
00255 
00256   // Make sure tmp1 points to a device before continuing.
00257   if(tmp1 == NULL)
00258   {
00259     if(tmp_devs.len() > 0)
00260       tmp1 = tmp_devs.pop();
00261     else
00262       error::fatal("No devices left after making connections in circuit::build_tree!");
00263   }
00264 
00265   // Connect remaining devices from tmp_devs list into block-diagonal device.
00266   while(tmp_devs.len() > 0)
00267   {
00268     tmp2 = tmp_devs.pop();
00269     tmp3 = new connection(*tmp1, *tmp2);
00270     del_stack.push(tmp3);
00271     
00272     tmp1 = tmp3;
00273   }
00274   tree_base = tmp1;
00275 
00276   tree_is_built = true;
00277 }
00278 
00279 
00280 //**************************************************************
00281 // calculating the circuit response
00282 
00283 
00284 const nport::data_info & circuit::get_data_info()
00285 {
00286   if(!tree_is_built) build_tree();
00287 
00288 
00289   // save the current device::T and set to local Temp
00290   parameter old_T(device::T);
00291   device::T = Temp;  // if Temp shadows T, this does nothing
00292 
00293   // get the info and adjust results based on temperature
00294   info = tree_base->get_data_info();
00295   if(info.noise && Temp != old_T) info.active = true;
00296 
00297   // Restore device::T and return info
00298   device::T = old_T;
00299   return info;
00300 }
00301 
00302 
00303 void circuit::calc(bool noise)
00304 {
00305   if(!tree_is_built) build_tree();
00306 
00307   // Verify that the number of ports left equals the size of the labels vector.
00308   if(tree_base->size() != labels.len())
00309     error::fatal("circuit::recalc(): Number of ports left after connecting circuit does"
00310                  " not equal the number of ports specified with circuit::add_port.");
00311 
00312   // save the current device::T and set to local Temp
00313   parameter old_T(device::T);
00314   device::T = Temp;  // if Temp shadows T, this does nothing
00315 
00316   // Get the unsorted data. What function we call to get the data
00317   // depends on whether or not we need tree_base to calculate the noise.
00318   const sdata& unsorted = (noise) ? tree_base->get_data() : tree_base->get_data_S();
00319   data.resize(unsorted.size());
00320 
00321   // sort the values into data, using the specified port assignments
00322   int i,j;
00323   int index1;
00324   int index2;
00325   for(i=1; i<=data.size(); i++)
00326   {
00327     index1 = tree_base->get_port(labels.get(i));
00328     for(j=1; j<=data.size(); j++) 
00329     {
00330       index2 = tree_base->get_port(labels.get(j));
00331       data.S[i][j] = unsorted.S.read(index1, index2);
00332       if(noise) data.C[i][j] = unsorted.C.read(index1, index2);
00333     }
00334     data.B[i] = unsorted.B.read(index1);
00335   }
00336 
00337   // now adjust normalizing impedance, if necessary:
00338   data.set_znorm(unsorted.get_znorm());
00339   data.change_norm(device::Z0);
00340 
00341   // Restore device::T
00342   device::T = old_T;
00343 }
00344 
00345 
00346 //**************************************************************
00347 
00348 cascade::cascade() : data_ptr_nport(), Temp(&T), last(0)
00349 {
00350   data.resize(2);
00351   data.S[1][2] = data.S[2][1] = 1.0;  // the branch equiv.
00352   data_ptr = &data;
00353   info.source = info.noise = info.active = false;  // for the branch equiv.
00354 }
00355 
00356 
00357 void cascade::recalc()
00358 {
00359   if (last) {
00360     data.resize(last->size());
00361     c.Temp = Temp;
00362     data_ptr = &c.get_data();
00363   }
00364 }
00365 
00366 
00367 void cascade::recalc_S()
00368 {
00369   if (last) {
00370     data.resize(last->size());
00371     c.Temp = Temp;
00372     data_ptr = &c.get_data_S();
00373   }
00374 }
00375 
00376 
00377 const nport::data_info & cascade::get_data_info()
00378 {
00379   if (last) {
00380     c.Temp = Temp;
00381     return c.get_data_info();
00382   }
00383   else
00384     return info;
00385 }
00386 
00387 
00388 cascade & cascade::add(nport & n)
00389 {
00390   if (last) {
00391     // not the first device added
00392     if (last->size() == 1)
00393       error::fatal("Can't add to a 1-port cascade.");
00394 
00395     switch (n.size()) {
00396 
00397     case 1: {
00398       c.pop_port();
00399       c.connect(*last, 2, n, 1);
00400       last = &n;
00401       break;
00402     }
00403 
00404     case 2: {
00405       c.pop_port();
00406       c.connect(*last, 2, n, 1);
00407       c.add_port(n, 2);
00408       last = &n;
00409       break;
00410     }
00411 
00412     default: {
00413       // improper size for n
00414       error::fatal("Device added to cascade must have 1 or 2 ports");
00415       break;
00416     }
00417 
00418     } //switch
00419 
00420   }
00421   else {
00422     // first device added
00423 
00424     switch (n.size()) {
00425 
00426     case 1: {
00427       c.add_port(n, 1);
00428       last = &n;
00429       break;
00430     }
00431 
00432     case 2: {
00433       c.add_port(n, 1);
00434       c.add_port(n, 2);
00435       last = &n;
00436       break;
00437     }
00438 
00439     default: {
00440       // improper size for n
00441       error::fatal("Device added to cascade must have 1 or 2 ports");
00442       break;
00443     }
00444 
00445     } //switch
00446 
00447   }
00448 
00449   return *this;
00450 }
00451 
00452 
00453 
00454 

Please direct comments and corrections to supermix@submm.caltech.edu
Go to the supermix home page
Generated by doxygen1.2.7