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 }
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 }
//分析电路 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(); //元器件工作 } }
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); } } }
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 }
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); } } }