package mods.eln.sim.mna;
import mods.eln.misc.Profiler;
import mods.eln.misc.Utils;
import mods.eln.sim.mna.component.Component;
import mods.eln.sim.mna.component.Delay;
import mods.eln.sim.mna.component.Resistor;
import mods.eln.sim.mna.component.VoltageSource;
import mods.eln.sim.mna.misc.IDestructor;
import mods.eln.sim.mna.misc.ISubSystemProcessFlush;
import mods.eln.sim.mna.misc.ISubSystemProcessI;
import mods.eln.sim.mna.state.State;
import mods.eln.sim.mna.state.VoltageState;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.QRDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class SubSystem {
public ArrayList<Component> component = new ArrayList<Component>();
public List<State> states = new ArrayList<State>();
public LinkedList<IDestructor> breakDestructor = new LinkedList<IDestructor>();
public ArrayList<SubSystem> interSystemConnectivity = new ArrayList<SubSystem>();
ArrayList<ISubSystemProcessI> processI = new ArrayList<ISubSystemProcessI>();
State[] statesTab;
RootSystem root;
double dt;
boolean matrixValid = false;
int stateCount;
RealMatrix A;
//RealMatrix I;
boolean singularMatrix;
double[][] AInvdata;
double[] Idata;
double[] XtempData;
boolean breaked = false;
ArrayList<ISubSystemProcessFlush> processF = new ArrayList<ISubSystemProcessFlush>();
public RootSystem getRoot() {
return root;
}
public SubSystem(RootSystem root, double dt) {
this.dt = dt;
this.root = root;
}
public void invalidate() {
matrixValid = false;
}
public void addComponent(Component c) {
component.add(c);
c.addedTo(this);
invalidate();
}
public void addState(State s) {
states.add(s);
s.addedTo(this);
invalidate();
}
public void removeComponent(Component c) {
component.remove(c);
c.quitSubSystem();
invalidate();
}
public void removeState(State s) {
states.remove(s);
s.quitSubSystem();
invalidate();
}
/*public void removeAll() {
for (Component c : component) {
c.disconnectFromSubSystem();
}
for (State s : states) {
s.disconnectFromSubSystem();
}
invalidate();
}*/
public void removeProcess(ISubSystemProcessI p) {
processI.remove(p);
invalidate();
}
public void addComponent(Iterable<Component> i) {
for (Component c : i) {
addComponent(c);
}
}
public void addState(Iterable<State> i) {
for (State s : i) {
addState(s);
}
}
public void addProcess(ISubSystemProcessI p) {
processI.add(p);
}
//double[][] getDataRef()
public void generateMatrix() {
stateCount = states.size();
Profiler p = new Profiler();
p.add("Inversse with " + stateCount + " state : ");
A = MatrixUtils.createRealMatrix(stateCount, stateCount);
//Adata = ((Array2DRowRealMatrix) A).getDataRef();
// X = MatrixUtils.createRealMatrix(stateCount, 1); Xdata =
// ((Array2DRowRealMatrix)X).getDataRef();
//I = MatrixUtils.createRealMatrix(stateCount, 1);
//Idata = ((Array2DRowRealMatrix) I).getDataRef();
Idata = new double[stateCount];
XtempData = new double[stateCount];
{
int idx = 0;
for (State s : states) {
s.setId(idx++);
}
}
for (Component c : component) {
c.applyTo(this);
}
// org.apache.commons.math3.linear.
try {
//FieldLUDecomposition QRDecomposition LUDecomposition RRQRDecomposition
RealMatrix Ainv = new QRDecomposition(A).getSolver().getInverse();
AInvdata = Ainv.getData();
singularMatrix = false;
} catch (Exception e) {
singularMatrix = true;
if (stateCount > 1) {
int idx = 0;
idx++;
Utils.println("//////////SingularMatrix////////////");
}
}
statesTab = new State[stateCount];
statesTab = states.toArray(statesTab);
matrixValid = true;
p.stop();
Utils.println(p);
}
public void addToA(State a, State b, double v) {
if (a == null || b == null)
return;
A.addToEntry(a.getId(), b.getId(), v);
//Adata[a.getId()][b.getId()] += v;
}
public void addToI(State s, double v) {
if (s == null) return;
Idata[s.getId()] = v;
//Idata[s.getId()][0] += v;
}
/*
* public void pushX(){
*
* }
*/
/*
* public void popX(){
*
* }
*/
public void step() {
stepCalc();
stepFlush();
}
public void stepCalc() {
Profiler profiler = new Profiler();
// profiler.add("generateMatrix");
if (!matrixValid) {
generateMatrix();
}
if (!singularMatrix) {
//profiler.add("generateMatrix");
for (int y = 0; y < stateCount; y++) {
Idata[y] = 0;
}
//profiler.add("generateMatrix");
for (ISubSystemProcessI p : processI) {
p.simProcessI(this);
}
// profiler.add("generateMatrix");
for (int idx2 = 0; idx2 < stateCount; idx2++) {
double stack = 0;
for (int idx = 0; idx < stateCount; idx++) {
stack += AInvdata[idx2][idx] * Idata[idx];
}
XtempData[idx2] = stack;
}
//Xtemp = Ainv.multiply(I);
}
profiler.stop();
//Utils.println(profiler);
}
public double solve(State pin) {
//Profiler profiler = new Profiler();
if (!matrixValid) {
generateMatrix();
}
if (!singularMatrix) {
for (int y = 0; y < stateCount; y++) {
Idata[y] = 0;
}
for (ISubSystemProcessI p : processI) {
p.simProcessI(this);
}
int idx2 = pin.getId();
double stack = 0;
for (int idx = 0; idx < stateCount; idx++) {
stack += AInvdata[idx2][idx] * Idata[idx];
}
return stack;
}
return 0;
}
//RealMatrix Xtemp;
public void stepFlush() {
if (!singularMatrix) {
for (int idx = 0; idx < stateCount; idx++) {
//statesTab[idx].state = Xtemp.getEntry(idx, 0);
statesTab[idx].state = XtempData[idx];
}
} else {
for (int idx = 0; idx < stateCount; idx++) {
statesTab[idx].state = 0;
}
}
for (ISubSystemProcessFlush p : processF) {
p.simProcessFlush();
}
}
public static void main(String[] args) {
// SubSystem s = new SubSystem(null, 0.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));
//
// s.step();
// s.step();
SubSystem s = new SubSystem(null, 0.1);
VoltageState n1, n2, n3, n4, n5;
VoltageSource u1;
Resistor r1, r2, r3;
Delay d1, d2;
s.addState(n1 = new VoltageState());
s.addState(n2 = new VoltageState());
s.addState(n3 = new VoltageState());
// s.addState(n4 = new VoltageState());
// s.addState(n5 = new VoltageState());
s.addComponent((u1 = new VoltageSource("")).setU(1).connectTo(n1, null));
s.addComponent((r1 = new Resistor()).setR(10).connectTo(n1, n2));
s.addComponent((d1 = new Delay()).set(1).connectTo(n2, n3));
s.addComponent((r2 = new Resistor()).setR(10).connectTo(n3, null));
//s.addComponent((d2 = new Delay()).set(10).connectTo(n4, n5));
//s.addComponent((r2 = new Resistor()).setR(10).connectTo(n5, null));
for (int idx = 0; idx < 100; idx++) {
s.step();
}
System.out.println("END");
s.step();
s.step();
s.step();
}
public boolean containe(State state) {
return states.contains(state);
}
public void setX(State s, double value) {
s.state = value;
}
public double getX(State s) {
return s.state;
}
public double getXSafe(State bPin) {
return bPin == null ? 0 : getX(bPin);
}
public boolean breakSystem() {
if (breaked) return false;
while (!breakDestructor.isEmpty()) {
breakDestructor.pop().destruct();
}
for (Component c : component) {
c.quitSubSystem();
}
for (State s : states) {
s.quitSubSystem();
}
if (root != null) {
for (Component c : component) {
c.returnToRootSystem(root);
}
for (State s : states) {
s.returnToRootSystem(root);
}
}
root.systems.remove(this);
invalidate();
breaked = true;
return true;
}
public void addProcess(ISubSystemProcessFlush p) {
processF.add(p);
}
public void removeProcess(ISubSystemProcessFlush p) {
processF.remove(p);
}
public double getDt() {
return dt;
}
static public class Th {
public double R, U;
public boolean isHighImpedance() {
return R > 1e8;
}
}
public Th getTh(State d, VoltageSource voltageSource) {
Th th = new Th();
double originalU = d.state;
double aU = 10;
voltageSource.setU(aU);
double aI = solve(voltageSource.getCurrentState());
double bU = 5;
voltageSource.setU(bU);
double bI = solve(voltageSource.getCurrentState());
double Rth = (aU - bU) / (bI - aI);
double Uth;
//if(Double.isInfinite(d.Rth)) d.Rth = Double.MAX_VALUE;
if (Rth > 10000000000000000000.0 || Rth < 0) {
Uth = 0;
Rth = 10000000000000000000.0;
} else {
Uth = aU + Rth * aI;
}
voltageSource.setU(originalU);
th.R = Rth;
th.U = Uth;
return th;
}
}