File indexing completed on 2024-04-28 05:43:15

0001 /***************************************************************************
0002  *   Copyright (C) 2003-2004 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "elementset.h"
0012 #include "bjt.h"
0013 #include "circuit.h"
0014 #include "element.h"
0015 #include "logic.h"
0016 #include "matrix.h"
0017 #include "nonlinear.h"
0018 
0019 #include <QDebug>
0020 
0021 #include <cassert>
0022 #include <cmath>
0023 #include <iostream>
0024 
0025 ElementSet::ElementSet(Circuit *circuit, const int n, const int m)
0026     : m_cb(m)
0027     , m_cn(n)
0028     , m_pCircuit(circuit)
0029 {
0030     int tmp = m_cn + m_cb;
0031 
0032     p_logicIn = nullptr;
0033 
0034     if (tmp) {
0035         p_A = new Matrix(m_cn, m_cb);
0036         p_b = new QuickVector(tmp);
0037         p_x = new QuickVector(tmp);
0038     } else {
0039         p_A = nullptr;
0040         p_x = p_b = nullptr;
0041     }
0042 
0043     m_cnodes = new CNode *[m_cn];
0044     for (uint i = 0; i < m_cn; i++) {
0045         m_cnodes[i] = new CNode(i);
0046     }
0047 
0048     m_cbranches = new CBranch *[m_cb];
0049     for (uint i = 0; i < m_cb; i++) {
0050         m_cbranches[i] = new CBranch(i);
0051     }
0052 
0053     m_ground = new CNode();
0054     m_ground->isGround = true;
0055     b_containsNonLinear = false;
0056 }
0057 
0058 ElementSet::~ElementSet()
0059 {
0060     const ElementList::iterator end = m_elementList.end();
0061     for (ElementList::iterator it = m_elementList.begin(); it != end; ++it) {
0062         // Note: By calling setElementSet(nullptr), we might have deleted it (the Element will commit
0063         // suicide when both the ElementSet and Component to which it belongs have deleted
0064         // themselves). So be very careful it you plan to do anything with the (*it) pointer
0065         if (*it)
0066             (*it)->elementSetDeleted();
0067     }
0068 
0069     for (uint i = 0; i < m_cn; i++)
0070         delete m_cnodes[i];
0071     for (uint i = 0; i < m_cb; i++)
0072         delete m_cbranches[i];
0073 
0074     delete[] m_cbranches;
0075     delete[] m_cnodes;
0076     delete[] p_logicIn;
0077     delete m_ground;
0078     if (p_A)
0079         delete p_A;
0080     if (p_b)
0081         delete p_b;
0082     if (p_x)
0083         delete p_x;
0084 }
0085 
0086 void ElementSet::setCacheInvalidated()
0087 {
0088     m_pCircuit->setCacheInvalidated();
0089 }
0090 
0091 void ElementSet::addElement(Element *e)
0092 {
0093     if (!e || m_elementList.contains(e))
0094         return;
0095     e->setElementSet(this);
0096     m_elementList.append(e);
0097     if (e->isNonLinear()) {
0098         b_containsNonLinear = true;
0099         m_cnonLinearList.append(static_cast<NonLinear *>(e));
0100     }
0101 }
0102 
0103 void ElementSet::createMatrixMap()
0104 {
0105     // mapping nolonger done, overly ambitious optimization...
0106 
0107     // And do our logic as well...
0108 
0109     m_clogic = 0;
0110     ElementList::iterator end = m_elementList.end();
0111     for (ElementList::iterator it = m_elementList.begin(); it != end; ++it) {
0112         if (dynamic_cast<LogicIn *>(*it))
0113             m_clogic++;
0114     }
0115 
0116     p_logicIn = new LogicIn *[m_clogic];
0117     int i = 0;
0118     for (ElementList::iterator it = m_elementList.begin(); it != end; ++it) {
0119         if (LogicIn *in = dynamic_cast<LogicIn *>(*it))
0120             p_logicIn[i++] = in;
0121     }
0122 }
0123 
0124 void ElementSet::doNonLinear(int maxIterations, double maxErrorV, double maxErrorI)
0125 {
0126     QuickVector *p_x_prev = new QuickVector(p_x);
0127 
0128     // And now tell the cnodes and cbranches about their new voltages & currents
0129     updateInfo();
0130 
0131     const NonLinearList::iterator end = m_cnonLinearList.end();
0132 
0133     int k = 0;
0134     do {
0135         // Tell the nonlinear elements to update its J, A and b from the newly calculated x
0136         for (NonLinearList::iterator it = m_cnonLinearList.begin(); it != end; ++it)
0137             (*it)->update_dc();
0138 
0139         *p_x = *p_b; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
0140 
0141         p_A->performLU();
0142         p_A->fbSub(p_x);
0143         updateInfo();
0144 
0145         // Now, check for convergence
0146         bool converged = true;
0147         for (unsigned i = 0; i < m_cn; ++i) {
0148             double diff = std::abs((*p_x_prev)[i] - (*p_x)[i]);
0149             if (diff > maxErrorI) {
0150                 converged = false;
0151                 break;
0152             }
0153         }
0154         if (converged) {
0155             for (unsigned i = m_cn; i < m_cn + m_cb; ++i) {
0156                 double diff = std::abs((*p_x_prev)[i] - (*p_x)[i]);
0157                 if (diff > maxErrorV) {
0158                     converged = false;
0159                     break;
0160                 }
0161             }
0162         }
0163 
0164         *p_x_prev = *p_x; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
0165 
0166         if (converged)
0167             break;
0168     } while (++k < maxIterations);
0169 
0170     delete p_x_prev;
0171 }
0172 
0173 bool ElementSet::doLinear(bool performLU)
0174 {
0175     if (b_containsNonLinear || (!p_b->isChanged() && ((performLU && !p_A->isChanged()) || !performLU)))
0176         return false;
0177 
0178     if (performLU)
0179         p_A->performLU();
0180 
0181     *p_x = *p_b; // <<< why does this code work, when I try it, I always get the default shallow copy.
0182 
0183     p_A->fbSub(p_x);
0184     updateInfo();
0185     p_b->setUnchanged();
0186 
0187     return true;
0188 }
0189 
0190 void ElementSet::updateInfo()
0191 {
0192     for (uint i = 0; i < m_cn; i++) {
0193         const double v = (*p_x)[i];
0194         if (std::isfinite(v)) {
0195             m_cnodes[i]->v = v;
0196         } else {
0197             (*p_x)[i] = 0.;
0198             m_cnodes[i]->v = 0.;
0199         }
0200     }
0201 
0202     for (uint i = 0; i < m_cb; i++) {
0203         // NOTE: I've used lowercase and uppercase "I" here, so be careful!
0204         const double I = (*p_x)[i + m_cn];
0205         if (std::isfinite(I)) {
0206             m_cbranches[i]->i = I;
0207         } else {
0208             (*p_x)[i + m_cn] = 0.;
0209             m_cbranches[i]->i = 0.;
0210         }
0211     }
0212 
0213     // Tell logic to check themselves
0214     for (uint i = 0; i < m_clogic; ++i) {
0215         p_logicIn[i]->check();
0216     }
0217 }
0218 
0219 void ElementSet::displayEquations()
0220 {
0221     std::cout.setf(std::ios_base::fixed);
0222     std::cout.precision(5);
0223     std::cout.setf(std::ios_base::showpoint);
0224     std::cout << "A x = b :" << std::endl;
0225     for (uint i = 0; i < m_cn + m_cb; i++) {
0226         std::cout << "( ";
0227         for (uint j = 0; j < m_cn + m_cb; j++) {
0228             const double value = p_A->g(i, j);
0229             //          if  ( value > 0 ) cout <<"+";
0230             //          else if ( value == 0 ) cout <<" ";
0231             std::cout.width(10);
0232             std::cout << value << " ";
0233         }
0234         std::cout << ") ( " << (*p_x)[i] << " ) = ( ";
0235         std::cout << (*p_b)[i] << " )" << std::endl;
0236     }
0237     std::cout << "A_LU:" << std::endl;
0238     p_A->displayLU();
0239 }