package mods.eln.sim.mna;
import mods.eln.misc.Profiler;
import mods.eln.misc.Utils;
import mods.eln.sim.ElectricalLoad;
import mods.eln.sim.mna.component.*;
import mods.eln.sim.mna.misc.IRootSystemPreStepProcess;
import mods.eln.sim.mna.misc.ISubSystemProcessFlush;
import mods.eln.sim.mna.state.State;
import mods.eln.sim.mna.state.VoltageState;
import java.util.*;
public class RootSystem {
double dt;
int interSystemOverSampling;
ArrayList<SubSystem> systems = new ArrayList<SubSystem>();
//public HashMap<Component, IDestructor> componentDestructor = new HashMap<Component, IDestructor>();
public Set<Component> addComponents = new HashSet<Component>();
public HashSet<State> addStates = new HashSet<State>();
static final int maxSubSystemSize = 100;
ArrayList<ISubSystemProcessFlush> processF = new ArrayList<ISubSystemProcessFlush>();
ArrayList<IRootSystemPreStepProcess> processPre = new ArrayList<IRootSystemPreStepProcess>();
public RootSystem(double dt, int interSystemOverSampling) {
this.dt = dt;
this.interSystemOverSampling = interSystemOverSampling;
}
public void addComponent(Component c) {
addComponents.add(c);
c.onAddToRootSystem();
for (State s : c.getConnectedStates()) {
if (s == null) continue;
if (s.getSubSystem() != null) {
breakSystems(s.getSubSystem());
}
}
}
public void removeComponent(Component c) {
SubSystem system = c.getSubSystem();
/*if (c.isAbstracted()) {
int i = 0;
i++;
}*/
if (system != null) {
breakSystems(system);
}
addComponents.remove(c);
c.onRemovefromRootSystem();
}
public void addState(State s) {
for (Component c : (ArrayList<Component>) s.getConnectedComponentsNotAbstracted().clone()) {
if (c.getSubSystem() != null)
breakSystems(c.getSubSystem());
}
addStates.add(s);
}
public void removeState(State s) {
SubSystem system = s.getSubSystem();
if (system != null) {
breakSystems(system);
}
addStates.remove(s);
}
public void generate() {
if (!addComponents.isEmpty() || !addStates.isEmpty()) {
//generateBreak();
//generateBreakLine();
Profiler p = new Profiler();
p.add("*** Generate ***");
generateLine();
generateSystems();
generateInterSystems();
int stateCnt = 0, componentCnt = 0;
for (SubSystem s : systems) {
stateCnt += s.states.size();
componentCnt += s.component.size();
}
p.stop();
Utils.println(p + " **** " + stateCnt + " " + componentCnt);
}
}
private boolean isValidForLine(State s) {
if (!s.canBeSimplifiedByLine()) return false;
List<Component> sc = s.getConnectedComponentsNotAbstracted();
if (sc.size() != 2) return false;
for (Component c : sc) {
if (false == c instanceof Resistor) {
return false;
}
}
return true;
}
private void generateBreakLine() {
}
private void generateLine() {
Set<State> stateScope = new HashSet<State>();
//HashSet<Resistor> resistorScope = new HashSet<Resistor>();
for (State s : addStates) {
if (isValidForLine(s)) {
stateScope.add(s);
}
}
while (!stateScope.isEmpty()) {
State sRoot = stateScope.iterator().next();
State sPtr = sRoot;
Resistor rPtr = (Resistor) sPtr.getConnectedComponentsNotAbstracted().get(0);
while (true) {
for (Component c : sPtr.getConnectedComponentsNotAbstracted()) {
if (c != rPtr) {
rPtr = (Resistor) c;
break;
}
}
State sNext = null;
if (sPtr != rPtr.aPin)
sNext = rPtr.aPin;
else if (sPtr != rPtr.bPin) sNext = rPtr.bPin;
if (sNext == null || sNext == sRoot || stateScope.contains(sNext) == false) break;
sPtr = sNext;
}
LinkedList<State> lineStates = new LinkedList<State>();
LinkedList<Resistor> lineResistors = new LinkedList<Resistor>();
lineResistors.add(rPtr);
//rPtr.lineReversDir = rPtr.aPin == sPtr;
while (true) {
lineStates.add(sPtr);
stateScope.remove(sPtr);
for (Component c : sPtr.getConnectedComponentsNotAbstracted()) {
if (c != rPtr) {
rPtr = (Resistor) c;
break;
}
}
lineResistors.add(rPtr);
//rPtr.lineReversDir = sPtr == rPtr.bPin;
State sNext = null;
if (sPtr != rPtr.aPin)
sNext = rPtr.aPin;
else if (sPtr != rPtr.bPin) sNext = rPtr.bPin;
if (sNext == null || stateScope.contains(sNext) == false) break;
sPtr = sNext;
}
if (lineResistors.getFirst() == lineResistors.getLast()) {
lineResistors.pop();
lineStates.pop();
}
//stateScope.removeAll(lineStates);
Line.newLine(this, lineResistors, lineStates);
}
}
/* private void generateBreak() {
for (Component c : (HashSet<Component>) addComponents.clone()) {
for (State s : c.getConnectedStates()) {
if (s == null) continue;
if (s.getSubSystem() != null) {
breakSystem(s.getSubSystem());
}
if (s.isAbstracted()) {
s.abstractedBy.breakAbstraction(this);
}
}
}
}*/
private void generateSystems() {
LinkedList<State> firstState = new LinkedList<State>();
for (State s : addStates) {
if (s.mustBeFarFromInterSystem()) {
firstState.add(s);
}
}
for (State s : firstState) {
if (s.getSubSystem() == null) {
buildSubSystem(s);
}
}
while (!addStates.isEmpty()) {
State root = addStates.iterator().next();
buildSubSystem(root);
}
}
public void generateInterSystems() {
Iterator<Component> ic = addComponents.iterator();
while (ic.hasNext()) {
Component c = ic.next();
if (!c.canBeReplacedByInterSystem()) {
System.out.println("ELN generateInterSystems ERROR");
}
new InterSystemAbstraction(this, (Resistor) c);
ic.remove();
}
}
public void step() {
Profiler profiler = new Profiler();
profiler.add("Generate");
generate();
profiler.add("interSystem");
for (int idx = 0; idx < interSystemOverSampling; idx++) {
for (IRootSystemPreStepProcess p : processPre) {
p.rootSystemPreStepProcess();
}
}
/* for (SubSystem s : systems) {
for (State state : s.states) {
Utils.print(state.state + " ");
}
}
Utils.println("");*/
profiler.add("stepCalc");
for (SubSystem s : systems) {
s.stepCalc();
}
profiler.add("stepFlush");
for (SubSystem s : systems) {
s.stepFlush();
}
profiler.add("simProcessFlush");
for (ISubSystemProcessFlush p : processF) {
p.simProcessFlush();
}
/* for (SubSystem s : systems) {
for (State state : s.states) {
Utils.print(state.state + " ");
}
}
Utils.println("");*/
profiler.stop();
//Utils.println(profiler);
}
private void buildSubSystem(State root) {
Set<Component> componentSet = new HashSet<Component>();
Set<State> stateSet = new HashSet<State>();
LinkedList<State> roots = new LinkedList<State>();
roots.push(root);
buildSubSystem(roots, componentSet, stateSet);
addComponents.removeAll(componentSet);
addStates.removeAll(stateSet);
SubSystem subSystem = new SubSystem(this, dt);
subSystem.addState(stateSet);
subSystem.addComponent(componentSet);
systems.add(subSystem);
}
private void buildSubSystem(LinkedList<State> roots, Set<Component> componentSet, Set<State> stateSet) {
boolean privateSystem = roots.getFirst().isPrivateSubSystem();
while (!roots.isEmpty()) {
State sExplored = roots.pollFirst();
stateSet.add(sExplored);
for (Component c : sExplored.getConnectedComponentsNotAbstracted()) {
if (privateSystem == false && roots.size() + stateSet.size() > maxSubSystemSize && c.canBeReplacedByInterSystem()) {
continue;
}
if (componentSet.contains(c)) continue;
boolean noGo = false;
for (State sNext : c.getConnectedStates()) {
if (sNext == null) continue;
if (sNext.getSubSystem() != null) {
noGo = true;
break;
}
if (sNext.isPrivateSubSystem() != privateSystem) {
noGo = true;
break;
}
}
if (noGo) continue;
componentSet.add(c);
for (State sNext : c.getConnectedStates()) {
if (sNext == null) continue;
if (stateSet.contains(sNext)) continue;
roots.addLast(sNext);
}
}
//roots = rootsNext;
}
}/*
private void buildSubSystem(State root,boolean withInterSystem, Set<Component> componentSet, Set<State> stateSet) {
if (stateSet.size() > maxSubSystemSize) {
return;
}
if (stateSet.contains(root) || findSubSystemWith(root) != null) return;
stateSet.add(root);
for (Component c : root.getConnectedComponents()) {
if (withInterSystem == false && c.canBeReplacedByInterSystem()) continue;
if (componentSet.contains(c)) continue;
boolean noGo = false;
for (State s : c.getConnectedStates()) {
if (s == null) continue;
if (s.getSubSystem() != null) {
noGo = true;
break;
}
}
if (noGo) continue;
componentSet.add(c);
for (State s : c.getConnectedStates()) {
if (s == null) continue;
buildSubSystem(s, withInterSystem, componentSet, stateSet);
}
}
}
*/
private SubSystem findSubSystemWith(State state) {
for (SubSystem s : systems) {
if (s.containe(state)) return s;
}
return null;
}
public void breakSystems(SubSystem sub) {
if (sub.breakSystem()) {
for (SubSystem s : sub.interSystemConnectivity) {
breakSystems(s);
}
}
}
public static void main(String[] args) {
RootSystem s = new RootSystem(0.1, 1);
VoltageState n1, n2;
VoltageSource u1;
Resistor r1, r2;
s.addState(n1 = new VoltageState());
s.addState(n2 = new VoltageState());
s.addComponent((u1 = new VoltageSource("")).setU(1).connectTo(n1, null));
s.addComponent((r1 = new Resistor()).setR(10).connectTo(n1, n2));
s.addComponent((r2 = new Resistor()).setR(20).connectTo(n2, null));
VoltageState n11, n12;
VoltageSource u11;
Resistor r11, r12, r13;
s.addState(n11 = new VoltageState());
s.addState(n12 = new VoltageState());
s.addComponent((u11 = new VoltageSource("")).setU(1).connectTo(n11, null));
s.addComponent((r11 = new Resistor()).setR(10).connectTo(n11, n12));
s.addComponent((r12 = new Resistor()).setR(30).connectTo(n12, null));
InterSystem i01;
s.addComponent((i01 = new InterSystem()).setR(10).connectTo(n2, n12));
for (int i = 0; i < 50; i++) {
s.step();
}
s.addComponent((r13 = new Resistor()).setR(30).connectTo(n12, null));
for (int i = 0; i < 50; i++) {
s.step();
}
s.step();
}
public int getSubSystemCount() {
return systems.size();
}
public void addProcess(ISubSystemProcessFlush p) {
processF.add(p);
}
public void removeProcess(ISubSystemProcessFlush p) {
processF.remove(p);
}
public void addProcess(IRootSystemPreStepProcess p) {
processPre.add(p);
}
public void removeProcess(IRootSystemPreStepProcess p) {
processPre.remove(p);
}
public boolean isRegistred(ElectricalLoad load) {
return load.getSubSystem() != null || addStates.contains(load);
}
}
//TODO: garbadge collector
//TODO: ghost suprresion