elementset.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003-2004 by David Saxton                               *
00003  *   david@bluehaze.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include "bjt.h"
00012 #include "circuit.h"
00013 #include "elementset.h"
00014 #include "element.h"
00015 #include "logic.h"
00016 #include "matrix.h"
00017 #include "nonlinear.h"
00018 
00019 #include <kdebug.h>
00020 
00021 #include <cmath>
00022 #include <iostream>
00023 #include <cassert>
00024 
00025 ElementSet::ElementSet(Circuit *circuit, const int n, const int m )
00026         : p_logicIn(0), m_pCircuit(circuit)
00027 {
00028 // Matrix class will abort if given 0 as parameter.
00029         int matsize = m + n;
00030         if(matsize) {
00031                 p_A = new Matrix(n, matsize);
00032                 p_b = new QuickVector(matsize);
00033                 p_x = new QuickVector(matsize);
00034         } else {
00035                 p_A = 0;
00036                 p_x = p_b = 0;
00037         }
00038 
00039         m_cn = n;
00040         m_cnodes = new CNode*[m_cn];
00041         for( uint i=0; i<m_cn; i++ ) {
00042                 m_cnodes[i] = new CNode(i);
00043         }
00044 
00045 //      m_cbranches = new CBranchList_T(m);
00046 
00047         m_cb = m;
00048         m_cbranches = new CBranch*[m_cb];
00049         for( uint i=0; i<m_cb; i++ ) {
00050                 m_cbranches[i] = new CBranch(i);
00051         }
00052 
00053         m_ground = new CNode();
00054         m_ground->isGround = true;
00055 
00056         b_containsNonLinear = false;
00057 }
00058 
00059 ElementSet::~ElementSet()
00060 {
00061         const ElementList::iterator end = m_elementList.end();
00062         for( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) {
00063                 // Note: By calling setElementSet(0), we might have deleted it (the Element will commit
00064                 // suicide when both the the ElementSet and Component to which it belongs have deleted
00065                 // themselves). So be very careful it you plan to do anything with the (*it) pointer
00066                 if(*it) (*it)->elementSetDeleted();
00067         }
00068 
00069         for( uint i=0; i<m_cn; i++ ) {
00070                 delete m_cnodes[i];
00071         }
00072         delete[] m_cnodes;
00073 
00074 //      delete m_cbranches;
00076         for( uint i=0; i<m_cb; i++ ) {
00077                 delete m_cbranches[i];
00078         }
00079         delete[] m_cbranches;
00081 
00082         delete[] p_logicIn;
00083 
00084         delete m_ground;
00085         if(p_A) delete p_A;
00086         if(p_b) delete p_b;
00087         if(p_x) delete p_x;
00088 }
00089 
00090 void ElementSet::setCacheInvalidated()
00091 {
00092         m_pCircuit->setCacheInvalidated();
00093 }
00094 
00095 void ElementSet::addElement( Element *e )
00096 {
00097         if(!e || m_elementList.contains(e)) return;
00098         e->setElementSet(this);
00099         m_elementList.append(e);
00100 
00101         if(e->isNonLinear()) {
00102                 b_containsNonLinear = true;
00103                 m_cnonLinearList.append(static_cast<NonLinear*>(e));
00104         }
00105 }
00106 
00107 void ElementSet::createMatrixMap()
00108 {
00109         p_A->createMap();
00110 
00111         // And do our logic as well...
00112         m_clogic = 0;
00113         ElementList::iterator end = m_elementList.end();
00114         for(ElementList::iterator it = m_elementList.begin(); it != end; ++it) {
00115                 if(dynamic_cast<LogicIn*>(*it)) m_clogic++;
00116         }
00117 
00118         p_logicIn = new LogicIn*[m_clogic];
00119         int i=0;
00120         for(ElementList::iterator it = m_elementList.begin(); it != end; ++it) {
00121                 if(LogicIn *in = dynamic_cast<LogicIn*>(*it)) p_logicIn[i++] = in;
00122         }
00123 }
00124 
00125 //#define CHECK
00126 
00127 void ElementSet::doNonLinear( int maxIterations, double maxErrorV, double maxErrorI )
00128 {
00129         // And now tell the cnodes and cbranches about their new voltages & currents
00130         updateInfo();
00131         const NonLinearList::iterator end = m_cnonLinearList.end();
00132         QuickVector *p_x_prev = 0;
00133         int k = 0;
00134         bool converged;
00135         do {
00136                 // Tell the nonlinear elements to update its J, A and b from the newly calculated x
00137                 for( NonLinearList::iterator it = m_cnonLinearList.begin(); it != end; ++it )
00138                         (*it)->update_dc();
00139 
00140 // must do deep copy. 
00141                 delete p_x;
00142                 p_x = new QuickVector(p_b);
00143 
00144                 p_A->performLU();
00145                 p_A->fbSub(p_x);
00146 
00147 #ifdef CHECK
00148 {
00149 QuickVector *result = new QuickVector(p_x->size());
00150 p_A->multiply(p_x,result);
00151 QuickVector *error = *p_b - result;
00152 delete result;
00153 const unsigned int end = error->size();
00154 double sum = 0;
00155 for(unsigned int i = 0; i < end; i++) {
00156         sum += fabs((*error)[i]);
00157 }
00158 delete error;
00159 assert(sum < EPSILON);
00160 }
00161 #endif
00162                 updateInfo();
00163 
00164                 if(p_x_prev) {
00165                 // Now, check for convergence
00166 // note: this code is a bit slicker that what was here but it doesn't honor
00167 // maxerrorI/V correctly. 
00168                         double sum = 0;
00169                         for( unsigned i = 0; i < m_cn+m_cb; ++i ) {
00170                                 sum += fabs( (*p_x_prev)[i] - (*p_x)[i]);
00171                         }
00172 
00173                         converged = (sum < EPSILON);
00174                         delete p_x_prev;
00175                 } else converged = false;
00176 
00177                 p_x_prev = new QuickVector(p_x);
00178 
00179         } while(!converged && (++k < maxIterations));
00180 
00181         if(p_x_prev) delete p_x_prev;
00182 }
00183 
00184 // ######################
00185 
00186 bool ElementSet::doLinear(bool performLU) {
00187         if( b_containsNonLinear || (!p_b->isChanged() && ((performLU && !p_A->isChanged()) || !performLU)) ) return false;
00188         
00189         if(performLU) p_A->performLU();
00190 
00191 // copy the new vector into the temporary vector...
00192         delete p_x;
00193         p_x = new QuickVector(p_b);
00194 
00195         p_A->fbSub(p_x);
00196 
00197 #ifdef CHECK
00198 {QuickVector *result = new QuickVector(p_x->size());
00199 p_A->multiply(p_x,result);
00200 QuickVector *error = *p_b - result;
00201 delete result;
00202 const unsigned int end = error->size();
00203 double sum = 0;
00204 for(unsigned int i = 0; i < end; i++) 
00205         sum += fabs((*error)[i]);
00206 delete error;
00207 kdDebug() << sum << endl;
00208 assert(sum < EPSILON);}
00209 #endif
00210 
00211         updateInfo();
00212         p_b->setUnchanged();
00213 
00214         return true;
00215 }
00216 
00217 void ElementSet::updateInfo()
00218 {
00219         for(uint i=0; i<m_cn; i++) {
00220                 const double v = (*p_x)[i];
00221                 if(std::isfinite(v)) {
00222                         m_cnodes[i]->v = v;
00223                 } else {
00224                         (*p_x)[i] = 0.;
00225                         m_cnodes[i]->v = 0.;
00226                 }
00227         }
00228 
00229         for( uint i=0; i<m_cb; i++ ) {
00230                 // NOTE: I've used lowercase and uppercase "I" here, so be careful!
00231                 const double I = (*p_x)[i+m_cn];
00232                 if(std::isfinite(I)) {
00233                         m_cbranches[i]->i = I;
00234                 } else {
00235                         (*p_x)[i+m_cn] = 0.;
00236                         m_cbranches[i]->i = 0.;
00237                 }
00238         }
00239 
00240         // Tell logic to check themselves
00241         for( uint i=0; i<m_clogic; ++i ) {
00242                 p_logicIn[i]->check();
00243         }
00244 }
00245 
00246 void ElementSet::displayEquations()
00247 {
00248         std::cout.setf(std::ios_base::fixed);
00249         std::cout.precision(5);
00250         std::cout.setf(std::ios_base::showpoint);
00251         std::cout << "A x = b :"<<std::endl;
00252         for(uint i=0; i<m_cn+m_cb; i++ ) {
00253                 std::cout << "( ";
00254                 for( uint j=0; j<m_cn+m_cb; j++ ) {
00255                         const double value = p_A->g(i,j);
00256 //                      if( value > 0 ) cout <<"+";
00257 //                      else if( value == 0 ) cout <<" ";
00258                         std::cout.width(10);
00259                         std::cout << value<<" ";
00260                 }
00261                 std::cout << ") ( "<<(*p_x)[i]<<" ) = ( ";
00262                 std::cout<<(*p_b)[i]<<" )"<<std::endl;
00263         }
00264         std::cout << "A_LU:"<<std::endl;
00265         p_A->displayLU();
00266 }
00267 

Generated on Tue May 8 17:05:29 2007 for KTechLab by  doxygen 1.5.1