/// <summary> /// Verifies that current subcircuit with given nodes as terminals represents valid SPICE subcircuit. That is: /// there are no floating nodes and there is a DC path between any two nodes not going through ground. /// </summary> /// <param name="terminals"></param> private CircuitTopologyException ValidateSubcircuit_Internal(int[] terminals) { // ground node must not be external terminal if (terminals == null) { throw new ArgumentNullException(nameof(terminals)); } if (terminals.Length == 0) { throw new ArgumentException("Subcircuit must have at least one terminal node."); } if (terminals.Any(n => n <= 0)) { throw new ArgumentOutOfRangeException("Terminals of Subcircuit must have positive ids."); } if (terminals.Any(n => n >= NodeCount)) { throw new ArgumentOutOfRangeException("There is no node with given id."); } if (validatedCircuit) { return(circuitException); } var neighbourghs = CircuitBuilderHelpers.GetNeighbourghs(NodeCount, Devices); neighbourghs[0].Clear(); // ignore connections to the ground node var components = CircuitBuilderHelpers.GetComponents(neighbourghs); components.RemoveAll(c => c[0] == 0); // remove ground component if (components.Count != 1) // incorrectly connected { return(new NotConnectedSubcircuitException(components)); } var branches = devices.SelectMany(e => e.GetBranchMetadata()).ToArray(); var cycle = GetVoltageCicrle(branches); return(cycle != null ? new VoltageBranchCycleException(cycle) : null); }
private IEnumerable <ICircuitDefinitionDevice> GetCurrentCutset(CircuitBranchMetadata[] branches) { var currentBranches = branches.Where(b => b.BranchType == BranchType.CurrentDefined).ToArray(); var neighbourghs = CircuitBuilderHelpers.GetNeighbourghs(NodeCount, devices); // remove current defined branches from the graph var nonCurrentElems = new HashSet <ICircuitDefinitionDevice>(devices); foreach (var e in currentBranches.Select(b => b.Device)) { nonCurrentElems.Remove(e); } foreach (var branch in currentBranches) { if (nonCurrentElems.Any(e => e.ConnectedNodes.Contains(branch.N1) && e.ConnectedNodes.Contains(branch.N2))) { continue; // some node bridges the same connection as this branch } neighbourghs[branch.N1].Remove(branch.N2); neighbourghs[branch.N2].Remove(branch.N1); } var components = CircuitBuilderHelpers.GetComponents(neighbourghs); // get indexes of components for faster lookup var componentIndexes = new int[NodeCount]; for (var i = 0; i < components.Count; i++) { foreach (var n in components[i]) { componentIndexes[n] = i; } } // throw away branches that do not connect nodes from different components var result = currentBranches .Where(b => componentIndexes[b.N1] != componentIndexes[b.N2]).Select(b => b.Device).ToArray(); return(result.Length > 0 ? result : null); }