コード例 #1
0
        public override bool Start()
        {
            #region Set exe files path

            if (this.IsNodeInPath)
            {
                this.NodeJsPath = FindInPath.Find("node.exe", MainWindow.WorkingDirectory, false);
            }
            if (this.IsLesscGlobal)
            {
                LesscPath = FindInPath.Find("lessc", MainWindow.WorkingDirectory, true, false);
                if (LesscPath.EndsWith(".bat", StringComparison.OrdinalIgnoreCase) || LesscPath.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase) || LesscPath.EndsWith(".com", StringComparison.OrdinalIgnoreCase))
                {
                    HashSet <string> possibleLesscLocations = FindPathInfo.InBat("%~dp0\\.\\", "lessc", LesscPath);
                    if (possibleLesscLocations != null)
                    {
                        foreach (string possibleLesscLocation in possibleLesscLocations)
                        {
                            string temp         = possibleLesscLocation.Replace("%~dp0\\.\\", string.Empty);
                            string tempFullPath = Path.GetDirectoryName(LesscPath) + Path.DirectorySeparatorChar + temp;
                            if (File.Exists(tempFullPath))
                            {
                                LesscPath = tempFullPath;
                                break;
                            }
                        }
                    }
                }
                ;
            }
            fileName  = this.NodeJsPath;
            arguments = "\"" + PathConverter.ConvertWinToUnix(this.LesscPath) + "\"";

            #endregion

            #region Merge paths

            if (String.IsNullOrEmpty(this.InputPath))
            {
                return(false);
            }
            this.workingDirectory = Path.GetDirectoryName(this.InputPath);
            this.InputPath        = PathConverter.ConvertWinToUnix(InputPath.Substring(this.workingDirectory.Length + 1));
            if (String.IsNullOrEmpty(this.OutputPath))
            {
                this.OutputPath  = this.InputPath.Remove(this.InputPath.LastIndexOf('.'));
                this.OutputPath += ".css";
            }

            #endregion

            #region Set arguments

            arguments += " " + this.AddParams + " ";
            if (this.IsMinified)
            {
                arguments += "-x ";
            }
            arguments += this.InputPath;

            #endregion

            #region Set process properties

            setupInfo(fileName, arguments, workingDirectory);

            this.IsStdoutDisplayed = false;

            this.StdoutReceived -= this.handleStdoutReceived;
            this.StdoutReceived += this.handleStdoutReceived;

            this.ProcessExited -= this.handleProcessExited;
            this.ProcessExited += this.handleProcessExited;

            this.dataReceived = null;
            return(run());

            #endregion
        }
コード例 #2
0
        public override bool Start()
        {
            #region Set EXE file path

            if (this.IsRubyInPath)
            {
                this.RubyPath = FindInPath.Find("ruby.exe", MainWindow.WorkingDirectory, false);
                this.SassPath = FindInPath.Find("sass", MainWindow.WorkingDirectory, true, true);
                if (SassPath.EndsWith(".bat", StringComparison.OrdinalIgnoreCase) || SassPath.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase) || SassPath.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase))
                {
                    HashSet <string> possibleSassLocations = FindPathInfo.InBat("\"ruby.exe\"", "sass\"", SassPath);
                    if (possibleSassLocations != null)
                    {
                        foreach (string possibleSassLocation in possibleSassLocations)
                        {
                            string temp = possibleSassLocation.Replace("\"", "").Replace("ruby.exe ", "");
                            if (File.Exists(temp))
                            {
                                SassPath = temp;
                                break;
                            }
                        }
                    }
                }
            }
            fileName  = RubyPath;
            arguments = "-e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) \"" + PathConverter.ConvertWinToUnix(SassPath) + "\"";

            #endregion

            #region Merge paths

            InputPath = !String.IsNullOrEmpty(InputPath) ? PathConverter.ConvertUnixToWin(InputPath) : ".";
            if (Directory.Exists(InputPath))
            {
                if (InputPath[InputPath.Length - 1] != '\\')
                {
                    InputPath += '\\';
                }
            }
            if (Directory.Exists(OutputPath))
            {
                if (OutputPath[OutputPath.Length - 1] != '\\')
                {
                    OutputPath += '\\';
                }
            }
            if (String.IsNullOrEmpty(OutputPath))
            {
                workingDirectory = Path.GetDirectoryName(InputPath);
                InputPath        = PathConverter.ConvertWinToUnix(Path.GetFileName(InputPath));
                OutputPath       = PathConverter.ConvertWinToUnix(Path.GetFileName(OutputPath));
            }
            else
            {
                workingDirectory = ComparePath.Compare(InputPath, OutputPath, '\\');
                int headerIndex = workingDirectory.Length;
                InputPath  = PathConverter.ConvertWinToUnix(InputPath.Substring(headerIndex));
                OutputPath = PathConverter.ConvertWinToUnix(OutputPath.Substring(headerIndex));
            }
            if (String.IsNullOrEmpty(InputPath))
            {
                InputPath = ".";
            }
            if (String.IsNullOrEmpty(OutputPath))
            {
                OutputPath = ".";
            }

            #endregion

            #region Set arguments

            fileName   = this.RubyPath;
            arguments += " " + this.AddParams;
            if (!String.IsNullOrEmpty(CodeStyle))
            {
                arguments += " --style " + CodeStyle;
            }
            if (this.IsUseLF)
            {
                arguments += " --unix-newlines";
            }
            if (!this.IsWatch && this.IsForce)
            {
                arguments += " --force";
            }
            if (this.IsNoCache)
            {
                arguments += " --no-cache";
            }
            if (this.IsWatch)
            {
                arguments += " --watch " + this.InputPath + ":" + this.OutputPath;
            }
            else
            {
                arguments += " --update " + this.InputPath + ":" + this.OutputPath;
            }

            #endregion

            #region Set process properties

            setupInfo(fileName, arguments, workingDirectory);

            return(run());

            #endregion
        }
コード例 #3
0
    //分析电路
    public static void analyzeCircuit()
    {
        if (elmList.Count == 0)                                                         //若元器件列表为空
        {
            return;
        }
        nodeList.Clear();                                       //清空结点列表
        int vscount = 0;                                        //电压源数量(将导线看做电压为0的电压源)

        //步骤一:找到电压源,确定起始元器件
        Debug.Log("步骤一");
        CircuitElm volt = null;                                 //电源源引用

        for (int i = 0; i < elmList.Count; i++)                 //遍历元器件列表
        {
            CircuitElm ce = getElm(i);                          //获取元器件
            if (ce.isDamaged)
            {
                elmList.Remove(ce);                                     //若元器件破损,在元器件列表中删除该元器件
                damageList.Add(ce);                                     //将损坏元器件添加进损坏列表
            }
            if (volt == null && ce.type == TYPES.VoltageElm)            //若找到了一个电源
            {
                volt = ce;                                              //为电压源赋值
            }
        }

        if (volt != null)                                                       //若找到电压源
        {
            CircuitNode cn = new CircuitNode();                                 //创建结点
            cn.name = volt.getPost(0);                                          //获取电压源负极
            nodeList.Add(cn);                                                   //添加进结点列表
        }
        else
        {
            CircuitNode cn = new CircuitNode();                                 //创建结点
            cn.name = null;                                                     //设置结点为空
            nodeList.Add(cn);                                                   //添加进结点列表
            return;
        }

        //步骤二:分配所有的结点和电压源
        Debug.Log("步骤二");
        for (int i = 0; i < elmList.Count; i++)                                 //遍历元器件列表
        {
            CircuitElm ce = getElm(i);                                          //获取元器件
            Debug.Log("元器件" + i + " " + getElm(i).getPost(0));
            int ivs   = ce.getVoltageSourceCount();                             //记录电压源数量
            int posts = ce.getPostCount();                                      //记录端点数量
            for (int j = 0; j < posts; j++)                                     //遍历元器件上的端口
            {
                string port = ce.getPost(j);                                    //获取元器件的端口
                int    k;
                for (k = 0; k < nodeList.Count; k++)                            //遍历结点列表
                {
                    CircuitNode cn = getCircuitNode(k);                         //获取k结点
                    if (cn.name.Equals(port))
                    {
                        break;                                    //从结点列表中找到了该结点
                    }
                }
                if (k == nodeList.Count)                                                //结点列表中无此结点
                {
                    CircuitNode cn = new CircuitNode();                                 //创建结点
                    cn.name = port;                                                     //标记结点名称
                    cn.links.Add(ce, j);                                                //添加进结点序列
                    ce.setNode(j, nodeList.Count);                                      //记录元器件的连接结点
                    nodeList.Add(cn);                                                   //将该结点添加到结点列表
                }
                else                                                                    //结点列表中有此结点
                {
                    getCircuitNode(k).links.Add(ce, j);                                 //添加结点链
                    ce.setNode(j, k);                                                   //记录元器件的连接结点

                    if (k == 0)                                                         //若结点为电源的负极
                    {
                        ce.setNodeVoltage(j, 0);                                        //端口j的电压为0
                    }
                }
            }
            vscount += ivs;                                                     //电压源数量累加
        }
        voltageSources   = new CircuitElm[vscount];                             //创建电压源数组
        vscount          = 0;                                                   //电压源数量置0
        circuitNonLinear = false;                                               //电路是否是非线性的

        Debug.Log("----------结点-----------");
        for (int i = 0; i < nodeList.Count; i++)
        {
            Debug.Log("结点" + i + " : " + getCircuitNode(i).name);
        }

        Debug.Log("---------元器件对应的结点----------");
        //for(int i = 0; i < elmList.Count; i++) {
        //    Debug.Log("元器件"+i+" : "+getElm(i).type+"  "+getElm(i).nodes[0]+"--"+ getElm(i).nodes[1]);
        //}

        //步骤三:初始电路矩阵
        Debug.Log("步骤三");
        for (int i = 0; i < elmList.Count; i++)                                 //遍历元器件
        {
            CircuitElm ce  = getElm(i);                                         //获取元器件
            int        ivs = ce.getVoltageSourceCount();                        //获取电压源数量
            for (int j = 0; j < ivs; j++)                                       //遍历电压源
            {
                voltageSources [vscount] = ce;                                  //为电压源数组赋值
                ce.setVoltageSource(j, vscount++);                              //设置电压源序号
            }
        }

        int matrixSize = nodeList.Count - 1 + vscount;                      //矩阵大小

        circuitMatrix     = new float[matrixSize, matrixSize];              //初始电路矩阵
        circuitRightSide  = new float[matrixSize];                          //初始电路右边矩阵
        origMatrix        = new float[matrixSize, matrixSize];
        origRightSide     = new float[matrixSize];
        circuitMatrixSize = circuitMatrixFullSize = matrixSize;             //初始电路矩阵大小
        circuitRowInfo    = new RowInfo[matrixSize];                        //初始行信息
        circuitPermute    = new int[matrixSize];                            //初始化电路交换数组

        for (int i = 0; i < matrixSize; i++)
        {
            circuitRowInfo [i] = new RowInfo();                                         //创建电路矩阵行信息对象
        }
        circuitNeedsMap = false;
        for (int i = 0; i < elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);                                                  //获取元器件
            ce.stamp();                                                                 //标记元器件,初始化电路矩阵
        }

        for (int i = 0; i < CirSim.circuitMatrixSize; i++)
        {
            string s = i + ": ";
            for (int j = 0; j < CirSim.circuitMatrixSize; j++)
            {
                s += CirSim.circuitMatrix [i, j] + " ";
            }
            s += " " + CirSim.circuitRightSide [i];
            Debug.Log(s);
        }

        //步骤四:处理图中未连接的结点
        Debug.Log("步骤四");
        bool[] closure     = new bool[nodeList.Count];
        bool[] tempclosure = new bool[nodeList.Count];
        bool   changed     = true;                                              //标志位

        closure [0] = true;                                                     //从第0个结点开始
        while (changed)
        {
            changed = false;                                                    //标志位置false
            for (int i = 0; i < elmList.Count; i++)                             //遍历所有元器件
            {
                CircuitElm ce = getElm(i);                                      //获取元器件
                for (int j = 0; j < ce.getPostCount(); j++)                     //遍历元器件的端口
                {
                    if (!closure [ce.getNode(j)])
                    {
                        if (ce.hasGroundConnection(j))                                          //若该端口连接到y阴极
                        {
                            closure [ce.getNode(j)] = changed = true;
                        }
                        continue;
                    }

                    for (int k = 0; k < ce.getPostCount(); k++)                         //再次遍历元器件端口
                    {
                        if (j == k)
                        {
                            continue;                                                           //若两个端口相等则继续
                        }
                        int kn = ce.getNode(k);                                                 //获取端口对应的结点
                        if (ce.getConnection(j, k) && !closure [kn])                            //若两端点相连并没有标记
                        {
                            closure [kn] = true;
                            changed      = true;
                        }
                    }
                }
            }
            if (changed)
            {
                continue;
            }

            //连接未连接的结点
            for (int i = 0; i < nodeList.Count; i++)
            {
                if (!closure [i])
                {
                    stampResistor(0, i, 1e8f);
                    closure [i] = true;
                    changed     = true;
                    break;
                }
            }
        }

        //步骤五:短路等无效连接的判断
        Debug.Log("步骤五");
        for (int i = 0; i < elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);                                                  //获取元器件
            //若为电压源或导线
            if ((ce.type == TYPES.VoltageElm && ce.getPostCount() == 2) ||
                (ce.type == TYPES.WireElm && ce.getPostCount() != 1))
            {
                FindPathInfo fpi = new FindPathInfo(FindPathInfo.VOLTAGE, ce, ce.getNode(1));
                if (fpi.findPath(ce.getNode(0)))                                        //判断是否短路
                //短路
                {
                    Utils.menuListener.PopTipUI("短  路");
                    Debug.Log("短路");
                    return;
                }
            }
        }

        //步骤六:简化矩阵
        Debug.Log("步骤六");
        for (int i = 0; i < matrixSize; i++)                                            //遍历矩阵的每一行
        {
            int     qm = -1, qp = -1;
            float   qv = 0;
            RowInfo re = circuitRowInfo [i];                                                    //获取每一行的信息
            if (re.lsChanges || re.dropRow || re.rsChanges)
            {
                continue;
            }
            float rsadd = 0;

            //寻找可以删除的行
            int j;
            for (j = 0; j < matrixSize; j++)                                                    //遍历矩阵的每一行
            {
                float q = circuitMatrix [i, j];                                                 //获取矩阵值
                if (circuitRowInfo [j].type == RowInfo.ROW_CONST)
                {
                    rsadd -= circuitRowInfo [j].value * q;
                    continue;
                }
                if (q == 0)
                {
                    continue;                                                                   //若矩阵值为0
                }
                if (qp == -1)                                                                   //记录第一个不为0的数值
                {
                    qp = j;                                                                     //记录第一个不为0的列
                    qv = q;                                                                     //记录该矩阵值
                    continue;
                }
                if (qm == -1 && q == -qv)                                                       //记录与qv互为相反数的列
                {
                    qm = j;                                                                     //列数
                    continue;
                }
                break;
            }
            if (j == matrixSize)                                                                //若遍历完了该行
            {
                if (qp == -1)
                {
                    //矩阵错误
                    Debug.Log("矩阵错误");
                    return;
                }
                RowInfo elt = circuitRowInfo [qp];                                              //获取行信息
                if (qm == -1)
                {
                    //一行只有一个常数
                    int k;
                    for (k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++)
                    {
                        qp  = elt.nodeEq;
                        elt = circuitRowInfo [qp];
                    }
                    if (elt.type == RowInfo.ROW_EQUAL)
                    {
                        elt.type = RowInfo.ROW_NORMAL;
                        continue;
                    }
                    if (elt.type != RowInfo.ROW_NORMAL)
                    {
                        continue;
                    }
                    elt.type  = RowInfo.ROW_CONST;                                              //标记为常数
                    elt.value = (circuitRightSide [i] + rsadd) / qv;                            //记录结点电压
                    circuitRowInfo [i].dropRow = true;                                          //删除该行
                    i = -1;
                }
                else if (circuitRightSide [i] + rsadd == 0)
                {
                    //若一行中只有两个非0的数值,并且两个数值互为相反数
                    if (elt.type != RowInfo.ROW_NORMAL)
                    {
                        int qq = qm;
                        qm  = qp;
                        qp  = qq;
                        elt = circuitRowInfo [qp];
                        if (elt.type != RowInfo.ROW_NORMAL)
                        {
                            //交换失败
                            continue;
                        }
                    }
                    elt.type   = RowInfo.ROW_EQUAL;                                             //标记行类型
                    elt.nodeEq = qm;                                                            //记录相等结点
                    circuitRowInfo [i].dropRow = true;                                          //删除标志位置true
                }
            }
        }

        //步骤七:确定新矩阵的大小
        Debug.Log("步骤七");
        int nn = 0;

        for (int i = 0; i != matrixSize; i++)                                   //遍历矩阵的行
        {
            RowInfo elt = circuitRowInfo [i];                                   //获取电路行信息
            if (elt.type == RowInfo.ROW_NORMAL)
            {
                elt.mapCol = nn++;
                continue;
            }
            if (elt.type == RowInfo.ROW_EQUAL)
            {
                RowInfo e2 = null;
                for (int j = 0; j != 100; j++)
                {
                    e2 = circuitRowInfo [elt.nodeEq];
                    if (e2.type != RowInfo.ROW_EQUAL)
                    {
                        break;
                    }
                    if (i == e2.nodeEq)
                    {
                        break;
                    }
                    elt.nodeEq = e2.nodeEq;
                }
            }
            if (elt.type == RowInfo.ROW_CONST)
            {
                elt.mapCol = -1;
            }
        }
        for (int i = 0; i != matrixSize; i++)
        {
            RowInfo elt = circuitRowInfo [i];
            if (elt.type == RowInfo.ROW_EQUAL)
            {
                RowInfo e2 = circuitRowInfo [elt.nodeEq];
                if (e2.type == RowInfo.ROW_CONST)
                {
                    elt.type   = e2.type;
                    elt.value  = e2.value;
                    elt.mapCol = -1;
                }
                else
                {
                    elt.mapCol = e2.mapCol;
                }
            }
        }

        //步骤八:创建新的简化矩阵
        Debug.Log("步骤八");
        Debug.Log("nn-----------------" + nn);
        int newsize = nn;

        float[,] newmatx = new float[newsize, newsize];
        float[] newrs = new float[newsize];
        int     ii    = 0;

        for (int i = 0; i != matrixSize; i++)
        {
            RowInfo rri = circuitRowInfo [i];
            if (rri.dropRow)
            {
                rri.mapRow = -1;
                continue;
            }
            newrs [ii] = circuitRightSide [i];
            rri.mapRow = ii;
            //System.out.println("Row " + i + " maps to " + ii);
            for (int j = 0; j != matrixSize; j++)
            {
                RowInfo ri = circuitRowInfo [j];
                if (ri.type == RowInfo.ROW_CONST)
                {
                    newrs [ii] -= ri.value * circuitMatrix [i, j];
                }
                else
                {
                    newmatx [ii, ri.mapCol] += circuitMatrix [i, j];
                }
            }
            ii++;
        }

        circuitMatrix    = newmatx;
        circuitRightSide = newrs;
        matrixSize       = circuitMatrixSize = newsize;
        for (int i = 0; i != matrixSize; i++)
        {
            origRightSide [i] = circuitRightSide [i];
        }
        for (int i = 0; i != matrixSize; i++)
        {
            for (int j = 0; j != matrixSize; j++)
            {
                origMatrix [i, j] = circuitMatrix [i, j];
            }
        }
        circuitNeedsMap = true;

        Debug.Log("--------新矩阵----------");
        for (int i = 0; i < CirSim.circuitMatrixSize; i++)
        {
            string s = i + ": ";
            for (int j = 0; j < CirSim.circuitMatrixSize; j++)
            {
                s += CirSim.circuitMatrix [i, j] + " ";
            }
            s += " " + CirSim.circuitRightSide [i];
            Debug.Log(s);
        }

        /*for (int i = 0; i != elmList.Count; i++) {
         * CircuitElm ce = getElm(i);
         * ce.doStep();
         * }*/

        if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute))
        {
            Debug.Log("矩阵计算错误");
            for (int i = 0; i < elmList.Count; i++)
            {
                getElm(i).stop();                  //停止所有元器件
            }
            return;
        }

        Debug.Log("--------LU分解后的矩阵----------");
        for (int i = 0; i < CirSim.circuitMatrixSize; i++)
        {
            string s = i + ": ";
            for (int j = 0; j < CirSim.circuitMatrixSize; j++)
            {
                s += CirSim.circuitMatrix [i, j] + " ";
            }
            s += " " + CirSim.circuitRightSide [i];
            Debug.Log(s);
        }

        //矩阵求解
        lu_solve(circuitMatrix, circuitMatrixSize, circuitPermute, circuitRightSide);

        //为每个结点的电压赋值
        for (int i = 0; i < circuitMatrixFullSize; i++)
        {
            RowInfo ri  = circuitRowInfo [i];                                                                           //获取行信息
            float   res = 0;
            if (ri.type == RowInfo.ROW_CONST)
            {
                res = ri.value;
            }
            else
            {
                res = circuitRightSide [ri.mapCol];
            }

            if (double.IsNaN(res))               //若是未知数结束循环
            {
                Debug.Log("res is NaN");
                break;
            }

            if (i < nodeList.Count - 1)
            {
                CircuitNode cn = getCircuitNode(i + 1);                                         //获取结点
                foreach (KeyValuePair <CircuitElm, int> kv in cn.links)                         //遍历结点上的所有端点
                {
                    kv.Key.setNodeVoltage(kv.Value, res);                                       //为结点赋予电压
                    Debug.Log(kv.Key.type + "--" + kv.Value + "         " + res);
                }
            }
            else
            {
                int j = i - (nodeList.Count - 1);
                voltageSources [j].setCurrent(j, res);
            }
        }

        for (int i = 0; i != elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);
            ce.doStep();
        }

        if (!isNext)
        {
            for (int i = 0; i < elmList.Count; i++)
            {
                CircuitElm ce = getElm(i);                                                                      //获取元器件脚本
                if (ce.type == TYPES.MusicChipElm || ce.type == TYPES.RecorderChipElm)                          //包含集成电路
                {
                    isNext = true;
                    analyzeCircuit();                                                                                   //重新分析电路
                    isNext = false;
                    return;
                }
            }
        }

        //运行元器件
        for (int i = 0; i < elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);                                  //获取元器件
            ce.work();                                                  //元器件工作
        }
    }
コード例 #4
0
ファイル: Circuit.cs プロジェクト: 741645596/Lab
        public void analyze()
        {
            if (elements.Count == 0)
            {
                return;
            }

            nodeList.Clear();

            #region 查找电源和接地元素
            // Search the circuit for a Ground, or Voltage sourcre
            CircuitElement voltageElm = null;
            bool           gotGround  = false;
            bool           gotRail    = false;
            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement elem = elements[i];
                if (elem is Ground)
                {
                    gotGround = true;
                    break;
                }

                if (elem is VoltageInput)                //RailElm in Java
                {
                    gotRail = true;
                }

                if (voltageElm == null && elem is Voltage)
                {
                    voltageElm = elem;
                }
            }

            // If no ground and no rails, then the voltage elm's first terminal is ground.
            // 没有电源(单),没有接地,但是有电源(双),那么电源的零点为接地点
            if (!gotGround && !gotRail && voltageElm != null)
            {
                CircuitNode cn = new CircuitNode();
                cn.lead = voltageElm.getLead(0);
                nodeList.Add(cn);
            }
            else
            {
                // If the circuit contains a ground, rail, or voltage
                // element, push a temporary node to the node list.
                CircuitNode cn = new CircuitNode();
                cn.lead = null; //Bin: 特殊节点,零点
                nodeList.Add(cn);
            }
            #endregion

            // At this point, there is 1 node in the list, the special `global ground` node.

            #region 电路节点和电源节点
            int vscount = 0;             // Number of voltage sources
            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement ce    = elements[i];
                int            leads = ce.getLeadCount();

                for (int j = 0; j != leads; j++)
                {
                    Lead lead = ce.getLead(j);
                    int  k;
                    for (k = 0; k != nodeList.Count; k++) //查找现有的每个节点,判断是否相连
                    {
                        //原Java版,这里用元器件的端点的坐标(XY)判断是否相连
                        //我们这里没有坐标,因此连接关系由Lead自己维护
                        CircuitNode cn = nodeList[k];
                        if (cn.lead != null)
                        {
                            FindConnection fc = new FindConnection(this, lead.Id);
                            if (fc.IsConnected(cn.lead.Id))
                            {
                                break;
                            }
                        }
                    }
                    if (k == nodeList.Count)  //没有找到现有的节点
                    {
                        CircuitNode cn = new CircuitNode();
                        cn.lead = lead;
                        CircuitNodeLink cnl = new CircuitNodeLink();
                        cnl.lead_ndx = j;
                        cnl.element  = ce;
                        cn.links.Add(cnl);
                        ce.setLeadNode(j, nodeList.Count);
                        nodeList.Add(cn); //这两行顺序不能颠倒
                    }
                    else
                    {
                        CircuitNodeLink cnl = new CircuitNodeLink();
                        cnl.lead_ndx = j;
                        cnl.element  = ce;
                        nodeList[k].links.Add(cnl);
                        ce.setLeadNode(j, k);
                        // if it's the ground node, make sure the node voltage is 0,
                        // cause it may not get set later
                        if (k == 0)
                        {
                            ce.setLeadVoltage(j, 0);
                        }
                    }
                }

                // Push an internal node onto the list for
                // each internal lead on the element.
                int internalLeads = ce.getInternalLeadCount();
                for (int j = 0; j != internalLeads; j++)
                {
                    CircuitNode cn = new CircuitNode();
                    cn.lead     = null;
                    cn.Internal = true;
                    CircuitNodeLink cnl = new CircuitNodeLink();
                    cnl.lead_ndx = j + leads;
                    cnl.element  = ce;
                    cn.links.Add(cnl);
                    ce.setLeadNode(cnl.lead_ndx, nodeList.Count);
                    nodeList.Add(cn); //这两行顺序不能颠倒
                }
                vscount += ce.getVoltageSourceCount();
            }
            #endregion

            // 创建电源节点数组
            // 同时判断电路是否线性

            // VoltageSourceId -> CircuitElement map
            voltageSources   = new CircuitElement[vscount];
            vscount          = 0;
            circuitNonLinear = false;


            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement ce = elements[i];
                if (ce.nonLinear())
                {
                    circuitNonLinear = true;
                }

                // Assign each votage source in the element a globally unique id,
                // (the index of the next open slot in voltageSources)
                for (int j = 0; j != ce.getVoltageSourceCount(); j++)
                {
                    voltageSources[vscount] = ce;
                    ce.setVoltageSource(j, vscount);
                    vscount++;
                }
            }

            #region 创建矩阵
            int matrixSize = nodeList.Count - 1 + vscount;

            // setup circuitMatrix
            circuitMatrix = new double[matrixSize][];
            for (int z = 0; z < matrixSize; z++)
            {
                circuitMatrix[z] = new double[matrixSize];
            }

            circuitRightSide = new double[matrixSize];

            // setup origMatrix
            origMatrix = new double[matrixSize][];
            for (int z = 0; z < matrixSize; z++)
            {
                origMatrix[z] = new double[matrixSize];
            }

            origRightSide = new double[matrixSize];

            // setup circuitRowInfo
            circuitRowInfo = new RowInfo[matrixSize];
            for (int i = 0; i != matrixSize; i++)
            {
                circuitRowInfo[i] = new RowInfo();
            }

            circuitPermute    = new int[matrixSize];
            circuitMatrixSize = circuitMatrixFullSize = matrixSize;
            circuitNeedsMap   = false;
            #endregion

            // Stamp linear circuit elements.
            for (int i = 0; i != elements.Count; i++)
            {
                elements[i].stamp(this);
            }

            #region 查找连接不正确的节点
            bool[] closure = new bool[nodeList.Count];
            bool   changed = true;
            closure[0] = true;
            while (changed)
            {
                changed = false;
                for (int i = 0; i != elements.Count; i++)
                {
                    CircuitElement ce = elements[i];
                    // loop through all ce's nodes to see if they are connected
                    // to other nodes not in closure
                    for (int leadX = 0; leadX < ce.getLeadCount(); leadX++)
                    {
                        if (!closure[ce.getLeadNode(leadX)])
                        {
                            if (ce.leadIsGround(leadX))
                            {
                                closure[ce.getLeadNode(leadX)] = changed = true;
                            }
                            continue;
                        }
                        for (int k = 0; k != ce.getLeadCount(); k++)
                        {
                            if (leadX == k)
                            {
                                continue;
                            }
                            int kn = ce.getLeadNode(k);
                            if (ce.leadsAreConnected(leadX, k) && !closure[kn])
                            {
                                closure[kn] = true;
                                changed     = true;
                            }
                        }
                    }
                }

                if (changed)
                {
                    continue;
                }

                // connect unconnected nodes
                for (int i = 0; i != nodeList.Count; i++)
                {
                    if (!closure[i] && !nodeList[i].Internal)
                    {
                        //System.out.println("node " + i + " unconnected");
                        stampResistor(0, i, 1E8);
                        closure[i] = true;
                        changed    = true;
                        break;
                    }
                }
            }
            #endregion

            #region  电路正确性检查
            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement ce = elements[i];

                // look for inductors with no current path
                if (ce is InductorElm)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.INDUCT, ce, ce.getLeadNode(1));
                    // first try findPath with maximum depth of 5, to avoid slowdowns
                    if (!fpi.findPath(ce.getLeadNode(0), 5) && !fpi.findPath(ce.getLeadNode(0)))
                    {
                        //System.out.println(ce + " no path");
                        ce.reset();
                    }
                }

                // look for current sources with no current path
                if (ce is CurrentSource)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.INDUCT, ce, ce.getLeadNode(1));
                    if (!fpi.findPath(ce.getLeadNode(0)))
                    {
                        panic("No path for current source!", ce);
                    }
                }

                // look for voltage source loops
                if ((ce is Voltage && ce.getLeadCount() == 2) || ce is Wire)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.VOLTAGE, ce, ce.getLeadNode(1));
                    if (fpi.findPath(ce.getLeadNode(0)))
                    {
                        panic("Voltage source/wire loop with no resistance!", ce);
                    }
                }

                // look for shorted caps, or caps w/ voltage but no R
                if (ce is CapacitorElm)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.SHORT, ce, ce.getLeadNode(1));
                    if (fpi.findPath(ce.getLeadNode(0)))
                    {
                        //System.out.println(ce + " shorted");
                        ce.reset();
                    }
                    else
                    {
                        fpi = new FindPathInfo(this, FindPathInfo.PathType.CAP_V, ce, ce.getLeadNode(1));
                        if (fpi.findPath(ce.getLeadNode(0)))
                        {
                            panic("Capacitor loop with no resistance!", ce);
                        }
                    }
                }
            }
            #endregion

            #region 简化矩阵 这块会导致电池无法并联,先去掉
            //for(int i = 0; i != matrixSize; i++) {
            //    int qm = -1, qp = -1;
            //    double qv = 0;
            //    RowInfo re = circuitRowInfo[i];

            //    if(re.lsChanges || re.dropRow || re.rsChanges)
            //        continue;

            //    double rsadd = 0;

            //    // look for rows that can be removed
            //    int leadX = 0;
            //    for(; leadX != matrixSize; leadX++) {

            //        double q = circuitMatrix[i][leadX];
            //        if(circuitRowInfo[leadX].type == RowInfo.ROW_CONST) {
            //            // keep a running total of const values that have been removed already
            //            rsadd -= circuitRowInfo[leadX].value * q;
            //            continue;
            //        }

            //        if(q == 0)
            //            continue;

            //        if(qp == -1) {
            //            qp = leadX;
            //            qv = q;
            //            continue;
            //        }

            //        if(qm == -1 && q == -qv) {
            //            qm = leadX;
            //            continue;
            //        }

            //        break;
            //    }

            //    if(leadX == matrixSize) {

            //        if(qp == -1)
            //            panic("Matrix error", null);

            //        RowInfo elt = circuitRowInfo[qp];
            //        if(qm == -1) {
            //            // we found a row with only one nonzero entry;
            //            // that value is a constant
            //            for(int k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++) {
            //                // follow the chain
            //                // System.out.println("following equal chain from " + i + " " + qp + " to " + elt.nodeEq);
            //                qp = elt.nodeEq;
            //                elt = circuitRowInfo[qp];
            //            }

            //            if(elt.type == RowInfo.ROW_EQUAL) {
            //                // break equal chains
            //                // System.out.println("Break equal chain");
            //                elt.type = RowInfo.ROW_NORMAL;
            //                continue;
            //            }

            //            if(elt.type != RowInfo.ROW_NORMAL) {
            //                //System.out.println("type already " + elt.type + " for " + qp + "!");
            //                continue;
            //            }

            //            elt.type = RowInfo.ROW_CONST;
            //            elt.value = (circuitRightSide[i] + rsadd) / qv;
            //            circuitRowInfo[i].dropRow = true;
            //            // System.out.println(qp + " * " + qv + " = const " + elt.value);
            //            i = -1; // start over from scratch
            //        } else if(circuitRightSide[i] + rsadd == 0) {
            //            // we found a row with only two nonzero entries, and one
            //            // is the negative of the other; the values are equal
            //            if(elt.type != RowInfo.ROW_NORMAL) {
            //                // System.out.println("swapping");
            //                int qq = qm;
            //                qm = qp;
            //                qp = qq;
            //                elt = circuitRowInfo[qp];
            //                if(elt.type != RowInfo.ROW_NORMAL) {
            //                    // we should follow the chain here, but this hardly
            //                    // ever happens so it's not worth worrying about
            //                    //System.out.println("swap failed");
            //                    continue;
            //                }
            //            }
            //            elt.type = RowInfo.ROW_EQUAL;
            //            elt.nodeEq = qm;
            //            circuitRowInfo[i].dropRow = true;
            //            // System.out.println(qp + " = " + qm);
            //        }
            //    }
            //}

            // == Find size of new matrix
            int nn = 0;
            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo elt = circuitRowInfo[i];
                if (elt.type == RowInfo.ROW_NORMAL)
                {
                    elt.mapCol = nn++;
                    // System.out.println("col " + i + " maps to " + elt.mapCol);
                    continue;
                }
                if (elt.type == RowInfo.ROW_EQUAL)
                {
                    RowInfo e2 = null;
                    // resolve chains of equality; 100 max steps to avoid loops
                    for (int leadX = 0; leadX != 100; leadX++)
                    {
                        e2 = circuitRowInfo[elt.nodeEq];
                        if (e2.type != RowInfo.ROW_EQUAL)
                        {
                            break;
                        }

                        if (i == e2.nodeEq)
                        {
                            break;
                        }

                        elt.nodeEq = e2.nodeEq;
                    }
                }
                if (elt.type == RowInfo.ROW_CONST)
                {
                    elt.mapCol = -1;
                }
            }

            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo elt = circuitRowInfo[i];
                if (elt.type == RowInfo.ROW_EQUAL)
                {
                    RowInfo e2 = circuitRowInfo[elt.nodeEq];
                    if (e2.type == RowInfo.ROW_CONST)
                    {
                        // if something is equal to a const, it's a const
                        elt.type   = e2.type;
                        elt.value  = e2.value;
                        elt.mapCol = -1;
                    }
                    else
                    {
                        elt.mapCol = e2.mapCol;
                    }
                }
            }

            // == Make the new, simplified matrix.
            int        newsize = nn;
            double[][] newmatx = new double[newsize][];
            for (int z = 0; z < newsize; z++)
            {
                newmatx[z] = new double[newsize];
            }

            double[] newrs = new double[newsize];
            int      ii    = 0;
            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo rri = circuitRowInfo[i];
                if (rri.dropRow)
                {
                    rri.mapRow = -1;
                    continue;
                }
                newrs[ii]  = circuitRightSide[i];
                rri.mapRow = ii;
                // System.out.println("Row " + i + " maps to " + ii);
                for (int leadX = 0; leadX != matrixSize; leadX++)
                {
                    RowInfo ri = circuitRowInfo[leadX];
                    if (ri.type == RowInfo.ROW_CONST)
                    {
                        newrs[ii] -= ri.value * circuitMatrix[i][leadX];
                    }
                    else
                    {
                        newmatx[ii][ri.mapCol] += circuitMatrix[i][leadX];
                    }
                }
                ii++;
            }
            #endregion

            #region             //// Copy matrix to orig ////
            circuitMatrix    = newmatx;
            circuitRightSide = newrs;
            matrixSize       = circuitMatrixSize = newsize;

            // copy `rightSide` to `origRightSide`
            for (int i = 0; i != matrixSize; i++)
            {
                origRightSide[i] = circuitRightSide[i];
            }

            // copy `matrix` to `origMatrix`
            for (int i = 0; i != matrixSize; i++)
            {
                for (int leadX = 0; leadX != matrixSize; leadX++)
                {
                    origMatrix[i][leadX] = circuitMatrix[i][leadX];
                }
            }
            #endregion

            circuitNeedsMap = true;
            _analyze        = false;

            // If the matrix is linear, we can do the lu_factor
            // here instead of needing to do it every frame.
            if (!circuitNonLinear)
            {
                if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute))
                {
                    panic("Singular matrix!", null);
                }
            }
        }
コード例 #5
0
        public override bool Start()
        {
            #region Set exe files path

            if (this.IsNodeInPath)
            {
                this.NodeJsPath = FindInPath.Find("node.exe", MainWindow.WorkingDirectory, false);
            }
            if (this.IsCoffeeGlobal)
            {
                CoffeePath = FindInPath.Find("coffee", MainWindow.WorkingDirectory, true, false);
                if (CoffeePath.EndsWith(".bat", StringComparison.OrdinalIgnoreCase) || CoffeePath.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase) || CoffeePath.EndsWith(".com", StringComparison.OrdinalIgnoreCase))
                {
                    HashSet <string> possibleCoffeeLocations = FindPathInfo.InBat("%~dp0\\.\\", "coffee", CoffeePath);
                    if (possibleCoffeeLocations != null)
                    {
                        foreach (string possibleCoffeeLocation in possibleCoffeeLocations)
                        {
                            string temp         = possibleCoffeeLocation.Replace("%~dp0\\.\\", string.Empty);
                            string tempFullPath = Path.GetDirectoryName(CoffeePath) + Path.DirectorySeparatorChar + temp;
                            if (File.Exists(tempFullPath))
                            {
                                CoffeePath = tempFullPath;
                                break;
                            }
                        }
                    }
                }
                ;
            }
            fileName  = this.NodeJsPath;
            arguments = "\"" + PathConverter.ConvertWinToUnix(this.CoffeePath) + "\"";

            #endregion

            #region Merge paths

            InputPath = !String.IsNullOrEmpty(InputPath) ? PathConverter.ConvertUnixToWin(InputPath) : ".";
            if (Directory.Exists(InputPath))
            {
                if (InputPath[InputPath.Length - 1] != '\\')
                {
                    InputPath += '\\';
                }
            }
            if (Directory.Exists(OutputPath))
            {
                if (OutputPath[OutputPath.Length - 1] != '\\')
                {
                    OutputPath += '\\';
                }
            }
            if (String.IsNullOrEmpty(OutputPath))
            {
                workingDirectory = Path.GetDirectoryName(InputPath);
                InputPath        = PathConverter.ConvertWinToUnix(Path.GetFileName(InputPath));
                OutputPath       = PathConverter.ConvertWinToUnix(Path.GetFileName(OutputPath));
            }
            else
            {
                workingDirectory = ComparePath.Compare(InputPath, OutputPath, '\\');
                int headerIndex = workingDirectory.Length;
                InputPath  = PathConverter.ConvertWinToUnix(InputPath.Substring(headerIndex));
                OutputPath = PathConverter.ConvertWinToUnix(OutputPath.Substring(headerIndex));
            }
            if (String.IsNullOrEmpty(InputPath))
            {
                InputPath = ".";
            }
            if (String.IsNullOrEmpty(OutputPath))
            {
                OutputPath = ".";
            }

            #endregion

            #region Set arguments

            arguments += " " + this.AddParams;
            if (this.IsBare)
            {
                arguments += " --bare";
            }
            if (this.IsWatch)
            {
                arguments += " --watch";
            }
            arguments += " --compile";
            if (!String.IsNullOrEmpty(OutputPath))
            {
                arguments += " --output " + this.OutputPath;
            }
            arguments += " " + this.InputPath;

            #endregion

            #region Set process properties

            setupInfo(fileName, arguments, workingDirectory);

            return(run());

            #endregion
        }
コード例 #6
0
        public void analyze()
        {
            if (elements.Count == 0)
            {
                return;
            }

            nodeList.Clear();
            List <bool>         internalList = new List <bool>();
            Action <long, bool> pushNode     = (id, isInternal) => {
                if (!nodeList.Contains(id))
                {
                    nodeList.Add(id);
                    internalList.Add(isInternal);
                }
            };

            #region             //// Look for Voltage or Ground element ////
            // Search the circuit for a Ground, or Voltage sourcre
            ICircuitElement voltageElm = null;
            bool            gotGround  = false;
            bool            gotRail    = false;
            for (int i = 0; i != elements.Count; i++)
            {
                ICircuitElement elem = elements[i];
                if (elem is Ground)
                {
                    gotGround = true;
                    break;
                }

                if (elem is VoltageInput)
                {
                    gotRail = true;
                }

                if (elem is Voltage && voltageElm == null)
                {
                    voltageElm = elem;
                }
            }

            // If no ground and no rails, then the voltage elm's first terminal is ground.
            if (!gotGround && !gotRail && voltageElm != null)
            {
                int    elm_ndx = elements.IndexOf(voltageElm);
                long[] ndxs    = nodeMesh[elm_ndx];
                pushNode(ndxs[0], false);
            }
            else
            {
                // If the circuit contains a ground, rail, or voltage
                // element, push a temporary node to the node list.
                pushNode(snowflake.NextId(), false);
            }
            #endregion

            // At this point, there is 1 node in the list, the special `global ground` node.

            #region             //// Nodes and Voltage Sources ////
            int vscount = 0;    // Number of voltage sources
            for (int i = 0; i != elements.Count; i++)
            {
                ICircuitElement elm   = elements[i];
                int             leads = elm.getLeadCount();

                // If the leadCount reported by the element does
                // not match the number of leads allocated,
                // resize the array.
                if (leads != nodeMesh[i].Length)
                {
                    long[] leadMap = nodeMesh[i];
                    Array.Resize(ref leadMap, leads);
                    nodeMesh[i] = leadMap;
                }

                // For each lead in the element
                for (int leadX = 0; leadX != leads; leadX++)
                {
                    long leadNode = nodeMesh[i][leadX];                            // Id of the node leadX is connected too
                    int  node_ndx = nodeList.IndexOf(leadNode);                    // Index of the leadNode in the nodeList
                    if (node_ndx == -1)
                    {
                        // If the nodeList doesn't contain the node, push it
                        // onto the list and assign it's new index to the lead.
                        elm.setLeadNode(leadX, nodeList.Count);
                        pushNode(leadNode, false);
                    }
                    else
                    {
                        // Otherwise, assign the lead the index of
                        // the node in the nodeList.
                        elm.setLeadNode(leadX, node_ndx);

                        if (leadNode == 0)
                        {
                            // if it's the ground node, make sure the
                            // node voltage is 0, cause it may not get set later
                            elm.setLeadVoltage(leadX, 0);                             // TODO: ??
                        }
                    }
                }

                // Push an internal node onto the list for
                // each internal lead on the element.
                int internalLeads = elm.getInternalLeadCount();
                for (int x = 0; x != internalLeads; x++)
                {
                    elm.setLeadNode(leads + x, nodeList.Count);
                    pushNode(snowflake.NextId(), true);
                }

                vscount += elm.getVoltageSourceCount();
            }
            #endregion

            // == Creeate the voltageSources array.
            // Also determine if circuit is nonlinear.

            // VoltageSourceId -> ICircuitElement map
            voltageSources = new ICircuitElement[vscount];
            vscount        = 0;

            circuitNonLinear = false;
            //for(int i = 0; i != elements.Count; i++) {
            //	ICircuitElement elem = elements[i];
            foreach (ICircuitElement elem in elements)
            {
                if (elem.nonLinear())
                {
                    circuitNonLinear = true;
                }

                // Assign each votage source in the element a globally unique id,
                // (the index of the next open slot in voltageSources)
                for (int leadX = 0; leadX != elem.getVoltageSourceCount(); leadX++)
                {
                    voltageSources[vscount] = elem;
                    elem.setVoltageSource(leadX, vscount++);
                }
            }

            #region             //// Matrix setup ////
            int matrixSize = nodeList.Count - 1 + vscount;

            // setup circuitMatrix
            circuitMatrix = new double[matrixSize][];
            for (int z = 0; z < matrixSize; z++)
            {
                circuitMatrix[z] = new double[matrixSize];
            }

            circuitRightSide = new double[matrixSize];

            // setup origMatrix
            origMatrix = new double[matrixSize][];
            for (int z = 0; z < matrixSize; z++)
            {
                origMatrix[z] = new double[matrixSize];
            }

            origRightSide = new double[matrixSize];

            // setup circuitRowInfo
            circuitRowInfo = new RowInfo[matrixSize];
            for (int i = 0; i != matrixSize; i++)
            {
                circuitRowInfo[i] = new RowInfo();
            }

            circuitPermute    = new int[matrixSize];
            circuitMatrixSize = circuitMatrixFullSize = matrixSize;
            circuitNeedsMap   = false;
            #endregion

            // Stamp linear circuit elements.
            for (int i = 0; i != elements.Count; i++)
            {
                elements[i].stamp(this);
            }

            #region             //// Determine nodes that are unconnected ////
            bool[] closure = new bool[nodeList.Count];
            bool   changed = true;
            closure[0] = true;
            while (changed)
            {
                changed = false;
                for (int i = 0; i != elements.Count; i++)
                {
                    ICircuitElement ce = elements[i];
                    // loop through all ce's nodes to see if they are connected
                    // to other nodes not in closure
                    for (int leadX = 0; leadX < ce.getLeadCount(); leadX++)
                    {
                        if (!closure[ce.getLeadNode(leadX)])
                        {
                            if (ce.leadIsGround(leadX))
                            {
                                closure[ce.getLeadNode(leadX)] = changed = true;
                            }
                            continue;
                        }
                        for (int k = 0; k != ce.getLeadCount(); k++)
                        {
                            if (leadX == k)
                            {
                                continue;
                            }
                            int kn = ce.getLeadNode(k);
                            if (ce.leadsAreConnected(leadX, k) && !closure[kn])
                            {
                                closure[kn] = true;
                                changed     = true;
                            }
                        }
                    }
                }

                if (changed)
                {
                    continue;
                }

                // connect unconnected nodes
                for (int i = 0; i != nodeList.Count; i++)
                {
                    if (!closure[i] && !internalList[i])
                    {
                        //System.out.println("node " + i + " unconnected");
                        stampResistor(0, i, 1E8);
                        closure[i] = true;
                        changed    = true;
                        break;
                    }
                }
            }
            #endregion

            #region             //// Sanity checks ////
            for (int i = 0; i != elements.Count; i++)
            {
                ICircuitElement ce = elements[i];

                // look for inductors with no current path
                if (ce is InductorElm)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.INDUCT, ce, ce.getLeadNode(1));
                    // first try findPath with maximum depth of 5, to avoid slowdowns
                    if (!fpi.findPath(ce.getLeadNode(0), 5) && !fpi.findPath(ce.getLeadNode(0)))
                    {
                        //System.out.println(ce + " no path");
                        ce.reset();
                    }
                }

                // look for current sources with no current path
                if (ce is CurrentSource)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.INDUCT, ce, ce.getLeadNode(1));
                    if (!fpi.findPath(ce.getLeadNode(0)))
                    {
                        panic("No path for current source!", ce);
                    }
                }

                // look for voltage source loops
                if ((ce is Voltage && ce.getLeadCount() == 2) || ce is Wire)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.VOLTAGE, ce, ce.getLeadNode(1));
                    if (fpi.findPath(ce.getLeadNode(0)))
                    {
                        panic("Voltage source/wire loop with no resistance!", ce);
                    }
                }

                // look for shorted caps, or caps w/ voltage but no R
                if (ce is CapacitorElm)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.SHORT, ce, ce.getLeadNode(1));
                    if (fpi.findPath(ce.getLeadNode(0)))
                    {
                        //System.out.println(ce + " shorted");
                        ce.reset();
                    }
                    else
                    {
                        fpi = new FindPathInfo(this, FindPathInfo.PathType.CAP_V, ce, ce.getLeadNode(1));
                        if (fpi.findPath(ce.getLeadNode(0)))
                        {
                            panic("Capacitor loop with no resistance!", ce);
                        }
                    }
                }
            }
            #endregion

            #region             //// Simplify the matrix //// =D
            for (int i = 0; i != matrixSize; i++)
            {
                int     qm = -1, qp = -1;
                double  qv = 0;
                RowInfo re = circuitRowInfo[i];

                if (re.lsChanges || re.dropRow || re.rsChanges)
                {
                    continue;
                }

                double rsadd = 0;

                // look for rows that can be removed
                int leadX = 0;
                for (; leadX != matrixSize; leadX++)
                {
                    double q = circuitMatrix[i][leadX];
                    if (circuitRowInfo[leadX].type == RowInfo.ROW_CONST)
                    {
                        // keep a running total of const values that have been removed already
                        rsadd -= circuitRowInfo[leadX].value * q;
                        continue;
                    }

                    if (q == 0)
                    {
                        continue;
                    }

                    if (qp == -1)
                    {
                        qp = leadX;
                        qv = q;
                        continue;
                    }

                    if (qm == -1 && q == -qv)
                    {
                        qm = leadX;
                        continue;
                    }

                    break;
                }

                if (leadX == matrixSize)
                {
                    if (qp == -1)
                    {
                        panic("Matrix error", null);
                    }

                    RowInfo elt = circuitRowInfo[qp];
                    if (qm == -1)
                    {
                        // we found a row with only one nonzero entry;
                        // that value is a constant
                        for (int k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++)
                        {
                            // follow the chain
                            // System.out.println("following equal chain from " + i + " " + qp + " to " + elt.nodeEq);
                            qp  = elt.nodeEq;
                            elt = circuitRowInfo[qp];
                        }

                        if (elt.type == RowInfo.ROW_EQUAL)
                        {
                            // break equal chains
                            // System.out.println("Break equal chain");
                            elt.type = RowInfo.ROW_NORMAL;
                            continue;
                        }

                        if (elt.type != RowInfo.ROW_NORMAL)
                        {
                            //System.out.println("type already " + elt.type + " for " + qp + "!");
                            continue;
                        }

                        elt.type  = RowInfo.ROW_CONST;
                        elt.value = (circuitRightSide[i] + rsadd) / qv;
                        circuitRowInfo[i].dropRow = true;
                        // System.out.println(qp + " * " + qv + " = const " + elt.value);
                        i = -1;                         // start over from scratch
                    }
                    else if (circuitRightSide[i] + rsadd == 0)
                    {
                        // we found a row with only two nonzero entries, and one
                        // is the negative of the other; the values are equal
                        if (elt.type != RowInfo.ROW_NORMAL)
                        {
                            // System.out.println("swapping");
                            int qq = qm;
                            qm  = qp;
                            qp  = qq;
                            elt = circuitRowInfo[qp];
                            if (elt.type != RowInfo.ROW_NORMAL)
                            {
                                // we should follow the chain here, but this hardly
                                // ever happens so it's not worth worrying about
                                //System.out.println("swap failed");
                                continue;
                            }
                        }
                        elt.type   = RowInfo.ROW_EQUAL;
                        elt.nodeEq = qm;
                        circuitRowInfo[i].dropRow = true;
                        // System.out.println(qp + " = " + qm);
                    }
                }
            }

            // == Find size of new matrix
            int nn = 0;
            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo elt = circuitRowInfo[i];
                if (elt.type == RowInfo.ROW_NORMAL)
                {
                    elt.mapCol = nn++;
                    // System.out.println("col " + i + " maps to " + elt.mapCol);
                    continue;
                }
                if (elt.type == RowInfo.ROW_EQUAL)
                {
                    RowInfo e2 = null;
                    // resolve chains of equality; 100 max steps to avoid loops
                    for (int leadX = 0; leadX != 100; leadX++)
                    {
                        e2 = circuitRowInfo[elt.nodeEq];
                        if (e2.type != RowInfo.ROW_EQUAL)
                        {
                            break;
                        }

                        if (i == e2.nodeEq)
                        {
                            break;
                        }

                        elt.nodeEq = e2.nodeEq;
                    }
                }
                if (elt.type == RowInfo.ROW_CONST)
                {
                    elt.mapCol = -1;
                }
            }

            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo elt = circuitRowInfo[i];
                if (elt.type == RowInfo.ROW_EQUAL)
                {
                    RowInfo e2 = circuitRowInfo[elt.nodeEq];
                    if (e2.type == RowInfo.ROW_CONST)
                    {
                        // if something is equal to a const, it's a const
                        elt.type   = e2.type;
                        elt.value  = e2.value;
                        elt.mapCol = -1;
                    }
                    else
                    {
                        elt.mapCol = e2.mapCol;
                    }
                }
            }

            // == Make the new, simplified matrix.
            int        newsize = nn;
            double[][] newmatx = new double[newsize][];
            for (int z = 0; z < newsize; z++)
            {
                newmatx[z] = new double[newsize];
            }

            double[] newrs = new double[newsize];
            int      ii    = 0;
            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo rri = circuitRowInfo[i];
                if (rri.dropRow)
                {
                    rri.mapRow = -1;
                    continue;
                }
                newrs[ii]  = circuitRightSide[i];
                rri.mapRow = ii;
                // System.out.println("Row " + i + " maps to " + ii);
                for (int leadX = 0; leadX != matrixSize; leadX++)
                {
                    RowInfo ri = circuitRowInfo[leadX];
                    if (ri.type == RowInfo.ROW_CONST)
                    {
                        newrs[ii] -= ri.value * circuitMatrix[i][leadX];
                    }
                    else
                    {
                        newmatx[ii][ri.mapCol] += circuitMatrix[i][leadX];
                    }
                }
                ii++;
            }
            #endregion

            #region             //// Copy matrix to orig ////
            circuitMatrix    = newmatx;
            circuitRightSide = newrs;
            matrixSize       = circuitMatrixSize = newsize;

            // copy `rightSide` to `origRightSide`
            for (int i = 0; i != matrixSize; i++)
            {
                origRightSide[i] = circuitRightSide[i];
            }

            // copy `matrix` to `origMatrix`
            for (int i = 0; i != matrixSize; i++)
            {
                for (int leadX = 0; leadX != matrixSize; leadX++)
                {
                    origMatrix[i][leadX] = circuitMatrix[i][leadX];
                }
            }
            #endregion

            circuitNeedsMap = true;
            _analyze        = false;

            // If the matrix is linear, we can do the lu_factor
            // here instead of needing to do it every frame.
            if (!circuitNonLinear)
            {
                if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute))
                {
                    panic("Singular matrix!", null);
                }
            }
        }