package com.lushprojects.circuitjs1.client;
import java.util.Vector;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;
// Circuit element made up of a composition of other circuit elements
// Using this will be (relatively) inefficient in terms of simulation performance because
// all the internal workings of the element are simulated from the individual components.
// However, it may allow some types of components to be more quickly programed in to the simulator
// than writing each component from scratch.
// It may also, eventually, provide a path to allow user created circuits to be
// re-imported in to the simuation as new circuit elements.
// Instatiations should:
// - Set the variable "diagonal" in the constructors
// - Override constructors to set up the elements posts/leads etc. and configure the contents of the CompositeElm
// - Override getDumpType, dump, draw, getPost, getInfo, setPoints, canViewInScope, getCurrentIntoPoint
public abstract class CompositeElm extends CircuitElm {
Vector<CircuitElm> compElmList = new Vector<CircuitElm>();
protected Vector<CircuitNode> compNodeList = new Vector<CircuitNode>();
protected int numPosts = 0;
protected int numNodes = 0;
protected Point posts[];
protected Vector<VoltageSourceRecord> voltageSources = new Vector<VoltageSourceRecord>();
CompositeElm(int xx, int yy, String s, int externalNodes[]) {
super(xx, yy);
loadComposite(null, s, externalNodes);
allocNodes();
}
public CompositeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st, String s, int externalNodes[]) {
super(xa, ya, xb, yb, f);
loadComposite(st, s, externalNodes);
allocNodes();
}
public void loadComposite(StringTokenizer stIn, String model, int externalNodes[]) {
HashMap<Integer, CircuitNode> compNodeHash = new HashMap<Integer, CircuitNode>();
StringTokenizer modelLinet = new StringTokenizer(model, "\r");
CircuitNode cn;
CircuitNodeLink cnLink;
VoltageSourceRecord vsRecord;
// Build compElmList and compNodeHash from input string
while (modelLinet.hasMoreTokens()) {
String line = modelLinet.nextToken();
StringTokenizer stModel = new StringTokenizer(line, " +\t\n\r\f");
String ceType = stModel.nextToken();
CircuitElm newce = CirSim.constructElement(ceType, 0, 0);
if (stIn!=null) {
int tint = newce.getDumpType();
String dumpedCe= stIn.nextToken();
StringTokenizer stCe = new StringTokenizer(dumpedCe, "_");
int flags = new Integer(stCe.nextToken()).intValue();
newce = CirSim.createCe(tint, 0, 0, 0, 0, flags, stCe);
}
compElmList.add(newce);
int thisPost = 0;
while (stModel.hasMoreTokens()) {
int nodeOfThisPost = new Integer(stModel.nextToken()).intValue();
cnLink = new CircuitNodeLink();
cnLink.num = thisPost;
cnLink.elm = newce;
if (!compNodeHash.containsKey(nodeOfThisPost)) {
cn = new CircuitNode();
cn.links.add(cnLink);
compNodeHash.put(nodeOfThisPost, cn);
} else {
cn = compNodeHash.get(nodeOfThisPost);
cn.links.add(cnLink);
}
thisPost++;
}
}
// Flatten compNodeHash in to compNodeList
numPosts = externalNodes.length;
for (int i = 0; i < externalNodes.length; i++) { // External Nodes First
if (compNodeHash.containsKey(externalNodes[i])) {
compNodeList.add(compNodeHash.get(externalNodes[i]));
compNodeHash.remove(externalNodes[i]);
} else
throw new IllegalArgumentException();
}
for (Entry<Integer, CircuitNode> entry : compNodeHash.entrySet()) {
int key = entry.getKey();
compNodeList.add(compNodeHash.get(key));
}
numNodes = compNodeList.size();
// CirSim.console("Dumping compNodeList");
// for (int i = 0; i < numNodes; i++) {
// CirSim.console("New node" + i + " Size of links:" + compNodeList.get(i).links.size());
// }
posts = new Point[numPosts];
// Enumerate voltage sources
for (int i = 0; i < compElmList.size(); i++) {
int cnt = compElmList.get(i).getVoltageSourceCount();
for (int j=0;j < cnt ; j++) {
vsRecord = new VoltageSourceRecord();
vsRecord.elm = compElmList.get(i);
vsRecord.vsNumForElement = j;
voltageSources.add(vsRecord);
}
}
}
public boolean nonLinear() {
return true; // Lets assume that any useful composite elements are
// non-linear
}
abstract public int getDumpType();
public String dump() {
String dumpStr=super.dump();
for (int i = 0; i < compElmList.size(); i++) {
String tstring = compElmList.get(i).dump().replace(' ', '_');
tstring = tstring.replaceFirst("[A-Za-z0-9]+_0_0_0_0_", ""); // remove unused tint_x1 y1 x2 y2 coords for internal components
dumpStr += " "+ tstring;
}
// for (int i=0; i<numPosts; i++) {
// dumpStr += " "+posts[i].x + " " + posts[i].y;
// }
return dumpStr;
}
public boolean getConnection(int n1, int n2) {
// TODO Find out if more sophisticated handling is needed here
// In the meantime subclasses should override this if they know nodes are not connected
return true;
}
// is n1 connected to ground somehow?
public boolean hasGroundConnection(int n1) {
Vector<CircuitNodeLink> cnLinks;
cnLinks = compNodeList.get(n1).links;
for (int i = 0; i < cnLinks.size(); i++) {
if (cnLinks.get(i).elm.hasGroundConnection(cnLinks.get(i).num))
return true;
}
return false;
}
public void reset() {
for (int i = 0; i < compElmList.size(); i++)
compElmList.get(i).reset();
}
int getPostCount() {
return numPosts;
}
int getInternalNodeCount() {
return numNodes - numPosts;
}
Point getPost(int n) {
return posts[n];
}
void setPost(int n, Point p) {
posts[n] = p;
}
void setPost(int n, int x, int y) {
posts[n].x = x;
posts[n].y = y;
}
public double getPower() {
double power;
power = 0;
for (int i = 0; i < compElmList.size(); i++)
power += compElmList.get(i).getPower();
return power;
}
public void stamp() {
for (int i = 0; i < compElmList.size(); i++)
compElmList.get(i).stamp();
}
public void doStep() {
for (int i = 0; i < compElmList.size(); i++)
compElmList.get(i).doStep();
}
public void stepFinished() {
for (int i = 0; i < compElmList.size(); i++)
compElmList.get(i).stepFinished();
}
abstract void getInfo(String arr[]);
public void setNode(int p, int n) {
// nodes[p] = n
Vector<CircuitNodeLink> cnLinks;
super.setNode(p, n);
cnLinks = compNodeList.get(p).links;
for (int i = 0; i < cnLinks.size(); i++) {
cnLinks.get(i).elm.setNode(cnLinks.get(i).num, n);
}
}
public void setNodeVoltage(int n, double c) {
// volts[n] = c;
Vector<CircuitNodeLink> cnLinks;
super.setNodeVoltage(n, c);
cnLinks = compNodeList.get(n).links;
for (int i = 0; i < cnLinks.size(); i++) {
cnLinks.get(i).elm.setNodeVoltage(cnLinks.get(i).num, c);
}
volts[n]=c;
}
public boolean canViewInScope() {
return false;
}
public void delete() {
for (int i = 0; i < compElmList.size(); i++)
compElmList.get(i).delete();
}
public int getVoltageSourceCount() {
return voltageSources.size();
}
// Find the component with the nth voltage
// and set the
// appropriate source in that component
void setVoltageSource(int n, int v) {
// voltSource(n) = v;
VoltageSourceRecord vsr;
vsr=voltageSources.get(n);
vsr.elm.setVoltageSource(vsr.vsNumForElement, v);
vsr.vsNode=v;
}
@Override
public void setCurrent(int vsn, double c) {
for (int i=0;i<voltageSources.size(); i++)
if (voltageSources.get(i).vsNode == vsn) {
voltageSources.get(i).elm.setCurrent(voltageSources.get(i).vsNumForElement, c);
}
}
// It is hard to write a general purpose getCurrentIntoNode routine because this is not defined
// for many circuit elements. Working-around by using getCurrentIntoPoint doesn't work for
// internal components as they don't have points.
// If all components in the composite have "getCurrentIntoNode" implemented then you can use this
// routine. If not then you must override with your own code.
double getCurrentIntoNode(int n) {
double c=0;
Vector<CircuitNodeLink> cnLinks;
cnLinks = compNodeList.get(n).links;
for (int i = 0; i < cnLinks.size(); i++) {
c+=cnLinks.get(i).elm.getCurrentIntoNode(cnLinks.get(i).num);
}
return c;
}
double getCurrentIntoPoint(int xa, int ya) {
for(int i=0; i<posts.length; i++) {
if (posts[i].x==xa && posts[i].y == ya)
return getCurrentIntoNode(i);
}
return 0;
}
}
class VoltageSourceRecord {
int vsNumForElement;
int vsNode;
CircuitElm elm;
}