--------------------------------------------------------------------------------
-- 81-714 Moscow and SPB electric schemes
--------------------------------------------------------------------------------
-- Copyright (C) 2013-2018 Metrostroi Team & FoxWorks Aerospace s.r.o.
-- Contains proprietary code. See license.txt for additional information.
--------------------------------------------------------------------------------
Metrostroi.DefineSystem("81_714_Electric")
TRAIN_SYSTEM.MVM = 1
TRAIN_SYSTEM.LVZ_1 = 2
TRAIN_SYSTEM.LVZ_2 = 3
TRAIN_SYSTEM.LVZ_3 = 4
TRAIN_SYSTEM.DOT_2 = 5
function TRAIN_SYSTEM:Initialize(typ1,typ2)
    self.TrainSolver = "81_717"
    self.ThyristorController = true
    self.Type = self.Type or self.MVM

    -- Load all functions from base
    Metrostroi.BaseSystems["Electric"].Initialize(self)
    for k,v in pairs(Metrostroi.BaseSystems["Electric"]) do
        if not self[k] and type(v) == "function" then
            self[k] = v
        end
    end

    self.SolvePowerCircuits = Metrostroi.BaseSystems["81_717_Electric"].SolvePowerCircuits
    self.SolveThyristorController = Metrostroi.BaseSystems["81_717_Electric"].SolveThyristorController
    self.Think = Metrostroi.BaseSystems["81_717_Electric"].Think
end

if CLIENT then return end
function TRAIN_SYSTEM:Inputs(...)
    return { "Type", "NoRT2", "HaveRO", "GreenRPRKR","X2PS", "HaveVentilation" }
end
function TRAIN_SYSTEM:Outputs(...)
    return Metrostroi.BaseSystems["81_717_Electric"].Outputs(self,...)
end
function TRAIN_SYSTEM:TriggerInput(name,value)
    if name == "Type" then
        self.Type = value
    end
    if name == "NoRT2" then self.NoRT2 = value > 0 end
    if name == "HaveRO" then self.HaveRO = value > 0 end
    if name == "GreenRPRKR" then self.GreenRPRKR = value > 0 end
    if name == "X2PS" then self.X2PS = value > 0 end
    if name == "HaveVentilation" then self.Vent = value > 0 end
end

-- Node values
local S = {}
-- Converts boolean expression to a number
local function C(x) return x and 1 or 0 end

local min = math.min
local max = math.max

function TRAIN_SYSTEM:SolveAllInternalCircuits(Train,dT,firstIter)
    local P     = Train.PositionSwitch
    local RheostatController = Train.RheostatController
    local RK    = RheostatController.SelectedPosition
    local B     = (Train.Battery.Voltage > 55) and 1 or 0
    local BO    = B*Train.VB.Value
    local T     = Train.SolverTemporaryVariables

    local isMVM = self.Type == 1
    local isDot2 = self.Type == 5

    local Panel = Train.Panel
    Panel.V1 = BO

    --Поездная часть
    S["33D"] = T[10]*Train.A54.Value*Train.A84.Value
    Train:WriteTrainWire(1, S["33D"]*C(Train.RV.Value~=1))
    Train:WriteTrainWire(20,S["33D"]*C(Train.RV.Value~=1))
    Train:WriteTrainWire(4, S["33D"]*C(Train.RV.Value==2)*Train.Start.Value)
    Train:WriteTrainWire(5, S["33D"]*C(Train.RV.Value==0)*Train.Start.Value)
    Train:WriteTrainWire(17,S["33D"]*Train.VozvratRP.Value)
    if isMVM then
        Train:WriteTrainWire(71,S["33D"]*Train.OtklBV.Value)
    end
    --Вагонная часть
    S["10A"] = BO*Train.A30.Value
    S["ZR"] = (1-Train.RRP.Value)+(B*Train.A39.Value*(1-Train.RPvozvrat.Value)*Train.RRP.Value)*-1

    S["1A"] = T[1]*Train.A1.Value*Train.IGLA_PCBK.KVC
    S["6A"] = T[6]*Train.A6.Value
    Train.TR1:TriggerInput("Set",S["6A"])
    --1A-PMU-1T-NR/RPU-1P(6^)

    S["1P"] = S["1A"]*P.PM*(Train.NR.Value+Train.RPU.Value)+S["6A"]*P.PT

    --1P-RK1-18-AVT-!RP-RKR-DR1-DR2-1G
    S["1G"] = S["1P"]*C(1 <= RK and RK <= 18)*Train.AVT.Value*(1-Train.RPvozvrat.Value)*Train.RKR.Value--FIXME
    S["1L"] = S["1G"]*C(RK==1)*(Train.KSB1.Value+Train.KSH1.Value)*Train.LK2.Value
    S["1Zh"] = (S["1L"]+S["1G"]*Train.LK3.Value)*S["ZR"]
    Train.LK1:TriggerInput("Set",S["1Zh"]*P.PM)
    Train.LK3:TriggerInput("Set",S["1Zh"])
    Train.LK4:TriggerInput("Set",S["1Zh"]*Train.LK3.Value)
    S["3A"] = T[3]*Train.A3.Value
    S["6G1"] = S["6A"]*P.PT*C(RK==1)
    self.ThyristorControllerWork = S["6G1"]*(Train.KSB1.Value+Train.KSB2.Value)*Train.LK2.Value
    S["6G2"] = S["6G1"]*(1-Train.RSU.Value)
    Train.KSB1:TriggerInput("Set",S["6G2"])
    Train.KSB2:TriggerInput("Set",S["6G2"])
    --20-A20-20A-Rp-20B
    S["20A"] = T[20]*Train.A20.Value*Train.IGLA_PCBK.KVC
    --Train.RPL:TriggerInput("Set",--[[ S["20A"]--]] BO*(1-Train.RPvozvrat.Value)*(Train.DR1.Value+Train.DR2.Value+(1-Train.BV.State)))
    if not isDot2 then
        Train.RPL:TriggerInput("Set",S["20A"]*(1-Train.RPvozvrat.Value)*(Train.DR1.Value+Train.DR2.Value+(1-Train.BV.State)))
    end
    S["20B"] = S["20A"]*(1-Train.RPvozvrat.Value)
    S["20K"] = S["20B"]*P.PS
    Train.LK2:TriggerInput("Set",S["20K"]*S["ZR"])
    Train.LK5:TriggerInput("Set",S["20B"]*Train.LK1.Value*S["ZR"])

    if self.X2PS then
        S["1M"] = C(1<=RK and RK<=5)*S["3A"]+S["20A"]*Train.KSH2.Value
        S["1R"] = (S["1A"]*C(RK==1)+S["1M"]*P.PP)*S["ZR"]
        Train.KSH1:TriggerInput("Set",S["1R"])
        Train.KSH2:TriggerInput("Set",S["1R"])
        P:TriggerInput("PP",S["3A"]*Train.LK5.Value*C(RK==18)*S["ZR"])--1A-1D
    else
        S["1M"] = C(1<=RK and RK<=5)*S["3A"]+T[10]*Train.KSH2.Value
        S["1R"] = (S["1A"]*C(RK==1)*P.PS + S["1M"]*P.PP)*S["ZR"]
        Train.KSH1:TriggerInput("Set",S["1R"])
        Train.KSH2:TriggerInput("Set",S["1R"])
        P:TriggerInput("PP",S["1A"]*C(RK==18)*S["ZR"])--1A-1D
    end


    local Reverser = Train.Reverser
    S["4A"] = T[4]*Train.A4.Value
    Reverser:TriggerInput("NZ",S["4A"]*Reverser.VP*(1-Train.LK1.Value)*S["ZR"])
    S["5A"] = T[5]*Train.A5.Value
    Reverser:TriggerInput("VP",S["5A"]*Reverser.NZ*(1-Train.LK1.Value)*S["ZR"])
    --Train.RKR:TriggerInput("Set",(S["4A"]*Reverser.NZ+S["5A"]*Reverser.VP)) --81-717.5(м) МСК
    if isDot2 then
        Train.RKR:TriggerInput("Set",(S["4A"]*Reverser.NZ+S["5A"]*Reverser.VP)*S["ZR"]) --81-717.5 Харько*S["ZR"]в
    else
        Train.RKR:TriggerInput("Set",(S["4A"]*Reverser.NZ+S["5A"]*Reverser.VP)*Train.BV.State*S["ZR"]) --81-717.5 Харько*S["ZR"]в
    end
    --+B
    S["1N"] = C(11<=RK and RK<=18)*(1-Train.LK4.Value)
    Train.RR:TriggerInput("Set",S["10A"]*S["1N"] + P.PS*Train.LK4.Value)

    S["5Zh"] = S["10A"]*(1-Train.LK3.Value)
    P:TriggerInput("PS",S["5Zh"]*(P.PP))
    P:TriggerInput("PM",S["5Zh"]*(1-Train.TR1.Value)*Train.KSH2.Value)
    P:TriggerInput("PT",S["5Zh"]*(P.PM)*(1-Train.KSH2.Value))
    --P:TriggerInput("PP",S["5Zh"]*(P.PM))
    S["2A"] = (T[2]+T[-2])*Train.A2.Value
    S["2T"] = S["2A"]*Train.TR1.Value
    Train.RSU:TriggerInput("Set",S["2T"]*Train.ThyristorBU5_6.Value)
    Train.RU:TriggerInput("Set",S["2T"])
    S["2B"] = S["2A"]*((1-Train.KSB1.Value)*(1-Train.KSB2.Value)+(1-Train.TR1.Value))

    S["2Ca"] = P.PS*C(1<=RK and RK<=17)*Train.RR.Value --CHECK
    S["2Cb"] = P.PP*(C(6<=RK and RK<=18)+C(2<=RK and RK<=5)*Train.KSH1.Value)*(1-Train.RR.Value) --CHECK
    S["2C"] = S["2B"]*(S["2Ca"]+S["2Cb"])*Train.LK4.Value
    S["10R"] = S["10A"]*(1-Train.LK3.Value)*C(2<=RK and RK<=18)*(1-Train.LK4.Value)
    S["2U"] = S["10R"]+S["2C"]*S["ZR"]
    Train.SR1:TriggerInput("Set",S["2U"])
    Train.RV1:TriggerInput("Set",S["2U"])
    S["2Zh"] = T[2]*Train.A2.Value*Train.TR1.Value*C(17<=RK and RK<=18)
    if self.NoRT2 then
        Train.PneumaticNo1:TriggerInput("Set",S["2Zh"]+T[48]*Train.A72.Value)
        Train:WriteTrainWire(-2,Train.A2.Value*Train.TR1.Value*C(17<=RK and RK<=18)*T[48]*Train.A72.Value)
    else
        Train.PneumaticNo1:TriggerInput("Set",S["2Zh"]+T[48]*Train.A72.Value*(1-Train.RT2.Value))
        Train:WriteTrainWire(-2,Train.A2.Value*Train.TR1.Value*C(17<=RK and RK<=18)*T[48]*Train.A72.Value*(1-Train.RT2.Value))
    end
    if isMVM then --UNREALISTIC
        S["8A"] = T[8]*Train.A8.Value*(1-Train.RV1.Value)*(1-Train.RT2r.Value)*(1-Train.RV3.Value)
    else
        S["8A"] = T[8]*Train.A8.Value*(1-Train.RV1.Value)*(1-Train.RT2.Value)*(1-Train.RV3.Value)
    end
    Train.PneumaticNo2:TriggerInput("Set",S["8A"]+T[39]*Train.A52.Value)
    Train.RV3:TriggerInput("Set",T[19]*Train.A19.Value)
    S["25A"] = T[25]*Train.A25.Value
    S["10X"] = (--[[ S["1N"]*P.PS+--]] Train.LK4.Value+C(RK==1)*Train.LK2.Value)
    Train["RRTpod"] = S["10A"]*RheostatController.RKM2*S["10X"]
    Train["RRTuderzh"] = S["25A"]
    Train["RUTpod"] = S["10A"]*RheostatController.RKM1*S["10X"]
    Train["RUTavt"] = Train.A70.Value*B
    Train.RRT:TriggerInput("Close",Train.RRTuderzh*Train.RRTpod)
    Train.RRT:TriggerInput("Open",(1-Train.RRTuderzh))

    Train.RRP:TriggerInput("Set",T[14]*Train.A14.Value)--14A
    --СДРК Б+ провод
    S["10A3"] = BO*Train.A28.Value
    S["10BG"] = S["10A3"]*(Train.TR1.Value + Train.RV1.Value)
    RheostatController:TriggerInput("MotorCoilState",min(1,S["10A"]*(S["10BG"]*Train.RR.Value - S["10BG"]*(1-Train.RR.Value))))
    Train.RVO:TriggerInput("Set",S["10A3"]*Train.NR.Value)
    self.ThyristorControllerPower = S["10A3"]
    --[[ S["10Ra"] = T[10]*RheostatController.RKM1
    S["10Rb"] = T[10]*Train.SR1.Value
    S["10RbA"] = S["10Rb"]*(1-Train.RRT.Value)*(1-Train.RUT.Value)+S["10Ra"]
    S["10RbB"] = S["10Rb"]*Train.RUT.Value
    S["10RB"] = S["10RbA"]+S["10RbB"]*Train.RRT.Value+S["10RbB"]*(1-Train.SR1.Value)

    S["10Rc"] = T[10]*Train.LK3.Value*C(RK>=18 or RK<=1)
    S["10RS"] = S["10Ra"]+S["10RB"]*(1-RheostatController.RKP)*S["10Rc"]--]]
    S["10Yu"] = S["10A"]*Train.SR1.Value
    S["10M"] = S["10Yu"]*(1-Train.RRT.Value)*(1-Train.RUT.Value)
    S["10N"] = S["10A"]*RheostatController.RKM1+S["10M"]
    S["10T"] = (Train.RUT.Value+Train.RRT.Value+(1-Train.SR1.Value))*(RheostatController.RKP)+S["10A"]*Train.LK3.Value*C(RK>=18 and RK<=1)
    RheostatController:TriggerInput("MotorState",S["10N"]+S["10T"]*(-10))

    Train.RZ_2:TriggerInput("Set",T[24]*(1-Train.LK4.Value))
    S["17A"] = T[17]*Train.A18.Value
    if not isDot2 then
        Train.BV:TriggerInput("Power",BO*Train.A80.Value)
        Train.BV:TriggerInput("Enable",S["17A"])
    end
    if isMVM then
        Train.BV:TriggerInput("Disable",T[71]*Train.A66.Value)
    end
    Train.RPvozvrat:TriggerInput("Open",S["17A"]) --FIXME Mayve more right RP code
    --
    --Вспом цепи
    Train:WriteTrainWire(10,BO*Train.A56.Value)

    if self.NoRT2 then
        Train:WriteTrainWire(48,Train.A72.Value*S["2Zh"]) --FIXME ARS
    else
        Train:WriteTrainWire(48,Train.A72.Value*S["2Zh"]*(1-Train.RT2.Value)) --FIXME ARS
    end

    Train:WriteTrainWire(22,T[10]*Train.A10.Value*Train.AK.Value)
    S["UO"] = T[10]*Train.A27.Value
    Train:WriteTrainWire(27,S["UO"]*Train.L_1.Value)
    S["36N"] = BO*Train.A45.Value
    Train:WriteTrainWire(36,S["36N"]*Train.BPSNon.Value)
    Train:WriteTrainWire(37,S["36N"]*Train.ConverterProtection.Value)

    if self.GreenRPRKR then
        S["10AN"] = Train.RPvozvrat.Value+(1-Train.RKR.Value) --81-717 Харьков
    else
        S["10AN"] = Train.RPvozvrat.Value --81-717 МСК
    end
    S["18A"] = (S["10AN"]*100+(1-Train.LK4.Value))*Train.A38.Value
    Train:WriteTrainWire(18,S["18A"])
    Panel.TW18 = S["18A"]
    Panel.GreenRP = S["10AN"]*S["UO"]

    --S["36N"] = BO*Train.A45.Value
    --Train:WriteTrainWire(37,Train.ConverterProtection.Value)
    --Train:WriteTrainWire(36,S["36N"]*(1-Train.BPSNon.Value))
    --Train:WriteTrainWire(69,T[36]*Train.BPSNon.Value)

    S["B9"] = B*Train.A53.Value
    S["B9a"] = S["B9"]*Train.VB.Value
    Train.KVC:TriggerInput("Set",S["B9a"])
    --Train.KUP:TriggerInput("Set",S["B9a"]*Train.A75.Value)
    S["D4"] = BO*Train.A13.Value
    Panel.RZP = T[36]*T[61]
    --[[S["14b"] = S["14a"]*Train.A17.Value
    S["D1"] = ["10"]*Train.A21.Value*KV["D-D1"]+S["14b"]*KRU["11/3-D1/1"]
    if isLVZ then
        Train:WriteTrainWire(16,S["D1"]*(Train.VUD1.Value*Train.VUD2.Value+AVO["16"]*RC2))
    else
        Train:WriteTrainWire(16,S["D1"]*(Train.VUD1.Value*Train.VUD2.Value))
    end
    Train:WriteTrainWire(12,S["D1"]*Train.KRZD.Value)
    S[31] = S["D1"]*(1-Train.DoorSelect.Value)
    S[32] = S["D1"]*Train.DoorSelect.Value
    Train:WriteTrainWire(31,S[31]*(Train.KDL.Value+Train.KDLR.Value+Train.VDL.Value))
    Train:WriteTrainWire(32,S[32]*Train.KDP.Value)

    S["F7"] = T[10]*Train.A29.Value*KV["F-F7"]+S["14b"]*KRU["11/3-FR1"]
    S["F1"] = S["B9"]*KV["B9-F1"]--]]

    Train:WriteTrainWire(34,Train.RKTT.Value+Train.DKPT.Value)
    Train:WriteTrainWire(28,T[-28]*Train.RD.Value)

    S[64] = S["UO"]*Train.BPT.Value
    Train:WriteTrainWire(64,S[64])
    Panel.BrW = S[64]

    --Вспом цепи приём
    if isDot2 then
        Panel.EmergencyLights = T[11]*Train.A15.Value*(1-Train.KPP.Value)
    else
        Panel.EmergencyLights = BO*Train.A49.Value*Train.A15.Value
    end
    Train.RPU:TriggerInput("Set",T[37]*Train.A37.Value)

    S["D6"] = S["D4"]*Train.BD.Value
    Train.RD:TriggerInput("Set",S["D6"])
    Panel.DoorsW = S["D4"]*(1-Train.RD.Value)
    Train.VDZ:TriggerInput("Set",T[16]*Train.A16.Value*(1-Train.RD.Value))
    S["12A"] = T[12]*Train.A12.Value
    S["31A"] = T[31]*Train.A31.Value
    S["32A"] = T[32]*Train.A32.Value
    Train.VDOL:TriggerInput("Set",S["31A"]+S["12A"])
    Train.VDOP:TriggerInput("Set",S["32A"]+S["12A"])
    Train:WriteTrainWire(31,S["12A"]*Train.A31.Value)
    Train:WriteTrainWire(32,S["12A"]*Train.A32.Value)

    S["36A"] = T[36]*Train.A51.Value*Train.RVO.Value--36
    Train.KVP:TriggerInput("Set",S["36A"]*Train.KPP.Value)
    Train.KPP:TriggerInput("Set",S["36A"]*(1-Train.RZP.Value)*Train.KVC.Value)
    S["27A"] = T[27]*Train.A50.Value
    Train.KO:TriggerInput("Set",S["27A"])
    --S["22A"] = (T[23]*Train.A23.Value+T[22]*Train.A22.Value) --FIXME 714

    Train.RV2:TriggerInput("Set",T[23]*Train.A23.Value)
    Train.KK:TriggerInput("Set",(
        T[22]*Train.A22.Value*(1-Train.RV2.Value)+
        T[23]*Train.A23.Value*Train.RV2.Value
    )*(1-Train.TRK.Value))

    --if isMVM then
        Panel.AnnouncerPlaying = T[13]
        Panel.AnnouncerBuzz = T[-13]
    --end

    --BPSN
    local BPSN = Train.PowerSupply
    Train.Battery:TriggerInput("Charge",BPSN.X2_2*Train.A24.Value*BO)
    BPSN:TriggerInput("5x2",BO*Train.A65.Value*Train.KVP.Value)
    Panel.MainLights = BPSN.X6_2*Train.KO.Value
    Train.RPU:TriggerInput("Set",T[37]*Train.A37.Value)
    Train.RZP:TriggerInput("Open",T[37]*Train.A37.Value*Train.RPU.Value)
    Train:WriteTrainWire(61,Train.RZP.Value)

    if self.Vent then
        Train.KV1:TriggerInput("Set",T[59]*Train.AV4.Value*Train.RVO.Value)
        Train.KV2:TriggerInput("Set",T[60]*Train.AV5.Value)
        Train.KV3:TriggerInput("Set",T[58]*Train.AV6.Value)
        S["AV2"] = T[10]*Train.AV2.Value
        Panel.M1_3 = S["AV2"]*Train.KV1.Value
        Panel.M4_7 = S["AV2"]*Train.KV2.Value+B*Train.AV3.Value*Train.KV3.Value
        Train.R1:TriggerInput("Set",S["AV2"]*C(Panel.M1_3 > 0.5 and Panel.M4_7 > 0.5))
        Train:WriteTrainWire(57,T[59]*(1-Train.R1.Value))
    end
    return S
end
function TRAIN_SYSTEM:SolveRKInternalCircuits(Train,dT,firstIter)
    local P     = Train.PositionSwitch
    local RheostatController = Train.RheostatController
    local RK    = RheostatController.SelectedPosition
    local B     = (Train.Battery.Voltage > 55) and 1 or 0
    local BO    = B*Train.VB.Value
    local T     = Train.SolverTemporaryVariables

    --Вагонная часть
    S["10A"] = BO*Train.A30.Value
    S["ZR"] = (1-Train.RRP.Value)+(B*Train.A39.Value*(1-Train.RPvozvrat.Value)*Train.RRP.Value)*-1


    S["1N"] = C(11<=RK and RK<=18)*(1-Train.LK4.Value)
    Train.RR:TriggerInput("Set",S["10A"]*S["1N"] + P.PS*Train.LK4.Value)

    S["2A"] = (T[2]+T[-2])*Train.A2.Value
    S["2B"] = S["2A"]*((1-Train.KSB1.Value)*(1-Train.KSB2.Value)+(1-Train.TR1.Value))

    S["2Ca"] = P.PS*C(1<=RK and RK<=17)*Train.RR.Value --CHECK
    S["2Cb"] = P.PP*(C(6<=RK and RK<=18)+C(2<=RK and RK<=5)*Train.KSH1.Value)*(1-Train.RR.Value) --CHECK
    S["2C"] = S["2B"]*(S["2Ca"]+S["2Cb"])*Train.LK4.Value
    S["10R"] = S["10A"]*(1-Train.LK3.Value)*C(2<=RK and RK<=18)*(1-Train.LK4.Value)
    S["2U"] = (S["10R"]+S["2C"])*S["ZR"]
    Train.SR1:TriggerInput("Set",S["2U"])
    Train.RV1:TriggerInput("Set",S["2U"])


    S["25A"] = T[25]*Train.A25.Value
    S["10X"] = (Train.LK4.Value+C(RK==1)*Train.LK2.Value)
    Train["RRTpod"] = S["10A"]*RheostatController.RKM2*S["10X"]
    Train["RRTuderzh"] = S["25A"]
    Train["RUTpod"] = S["10A"]*RheostatController.RKM1*S["10X"]
    Train.RRT:TriggerInput("Close",Train.RRTuderzh*Train.RRTpod)
    Train.RRT:TriggerInput("Open",(1-Train.RRTuderzh))

    --СДРК Б+ провод
    S["10A3"] = BO*Train.A28.Value
    S["10BG"] = S["10A3"]*(Train.TR1.Value + Train.RV1.Value)
    RheostatController:TriggerInput("MotorCoilState",min(1,S["10A"]*(S["10BG"]*Train.RR.Value - S["10BG"]*(1-Train.RR.Value))))

    S["10Yu"] = S["10A"]*Train.SR1.Value
    S["10M"] = S["10Yu"]*(1-Train.RRT.Value)*(1-Train.RUT.Value)
    S["10N"] = S["10A"]*RheostatController.RKM1+S["10M"]
    S["10T"] = (Train.RUT.Value+Train.RRT.Value+(1-Train.SR1.Value))*(RheostatController.RKP)+S["10A"]*Train.LK3.Value*C(RK>=18 and RK<=1)
    RheostatController:TriggerInput("MotorState",S["10N"]+S["10T"]*(-10))

    return S
end

local wires = {10,11,1,6,3,20,4,5,-2,2,48,8,39,19,25,13,-13,14,24,17,71,36,-28,37,16,12,31,32,69,27,23,22,23,37,59,60,58,61}
function TRAIN_SYSTEM:SolveInternalCircuits(Train,dT,firstIter)
    local T     = Train.SolverTemporaryVariables
    if not T then
        T = {}
        for i,v in ipairs(wires) do T[v] = 0 end
        Train.SolverTemporaryVariables = T
    end
    if firstIter then
        for i,v in ipairs(wires) do T[v] = min(Train:ReadTrainWire(v),1) end
        self:SolveAllInternalCircuits(Train,dT)
    else
        self:SolveRKInternalCircuits(Train,dT)
    end
end