frappy/frappy_psi/dilution_statemachine.py

301 lines
10 KiB
Python

# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Andrea Plank <andrea.plank@psi.ch>
#
# *****************************************************************************
from frappy.core import Drivable, Parameter, EnumType, Attached, FloatRange, \
Command, IDLE, BUSY, WARN, ERROR, Property
from frappy.datatypes import StatusType, EnumType, ArrayOf, BoolType, IntRange
from frappy.states import StateMachine, Retry, Finish, status_code, HasStates
from frappy.lib.enum import Enum
from frappy.errors import ImpossibleError
import time
Targetstates = Enum(
SORBPUMP = 0,
CONDENSE = 1,
CIRCULATE = 2,
REMOVE = 3,
MANUAL = 4,
TEST = 5,
STOP = 6,
)
class Dilution(HasStates, Drivable):
condenseline_pressure = Attached()
condense_valve = Attached()
dump_valve = Attached()
circulate_pump = Attached()
compressor = Attached(mandatory=(False))
turbopump = Attached(mandatory=(False))
condenseline_valve = Attached()
circuitshort_valve = Attached()
still_pressure = Attached()
#ls372 = Attached()
V5 = Attached() #Name noch ändern!!!
p1 = Attached() #Name noch ändern!!!
condensing_p_low = Property('Lower limit for condenseline pressure', IntRange())
condensing_p_high = Property('Lower limit for condenseline pressure', IntRange())
target = Parameter('target state', EnumType(Targetstates))
value = Parameter('target state', EnumType(Targetstates))
init = True
def earlyInit(self):
super().earlyInit()
def read_value(self):
return self.value
def write_target(self, target):
"""
if (target == Targetstates.SORBPUMP):
if self.value == target:
return self.target
self.start_machine(self.sorbpump)
self.value = Targetstates.SORBPUMP
return self.value
"""
if (target == Targetstates.TEST):
self.value = Targetstates.TEST
self.init = True
self.start_machine(self.test)
if (target == Targetstates.REMOVE):
if self.value == target:
return target
if self.value != Teststates.CIRCULATE:
self.final_status(WARN, "state before is not circulate")
return self.value
self.value = Targetstates.REMOVE
self.init = True
self.start_machine(self.remove)
elif (target == Targetstates.CIRCULATE):
if self.value == target:
return target
self.value = Targetstates.CIRCULATE
self.init = True
self.start_machine(self.circulate)
elif (target == Targetstates.CONDENSE):
if self.value == target:
return target
self.value = Targetstates.CONDENSE
self.init = True
self.start_machine(self.condense)
elif(target == Targetstates.MANUAL):
self.value = Targetstates.MANUAL
self.stop_machine()
elif (target == Targetstates.STOP):
self.value = Targetstates.STOP
self.stop_machine()
return self.value
"""
@status_code(BUSY, 'sorbpump state')
def sorbpump(self, state):
#Heizt Tsorb auf und wartet ab.
if self.init:
self.ls372.write_target(40) #Setze Tsorb auf 40K
self.start_time = self.now
self.init = false
return Retry
if self.now - self.start_time < 2400: # 40 Minuten warten
return Retry
self.ls372.write_target(0)
if self.ls372.read_value() > 10: # Warten bis Tsorb unter 10K
return Retry
return self.condense
"""
@status_code(BUSY, 'test mode')
def test(self, state):
"Nur zum testen, ob UI funktioniert"
self.init = False
self.condense_valve.write_target(1)
time.sleep(1)
self.condense_valve.write_target(0)
self.dump_valve.write_target(1)
time.sleep(1)
self.dump_valve.write_target(0)
self.compressor.write_target(1)
return True
@status_code(BUSY, 'condense mode')
def wait_for_condense_line_pressure(self, state):
if (self.condenseline_pressure.read_value > 500):
return Retry
return self.circulate
def initialize_condense_valves(self):
return True
@status_code(BUSY, 'condense state')
def condense(self, state):
"""Führt das Kondensationsverfahren durch."""
if self.init:
self.initialize_condense_valves()
self.circuitshort_valve.write_target(0)
self.dump_valve.write_target(0)
self.condense_valve.write_target(0)
self.condenseline_valve.write_target(1)
self.V5.write_target(1)
if (self.compressor is not None):
self.compressor.write_target(1)
self.circulate_pump.write_target(1)
self.init = False
return Retry
if self.condenseline_pressure.read_value() < self.condensing_p_low:
self.condense_valve.write_target(1)
elif (self.condenseline_pressure.read_value() > self.condensing_p_high):
self.condense_valve.write_target(0)
if (self.p1.read_value() > 20):
return Retry
self.condense_valve.write_target(1)
if (self.turbopump is not None):
if (self.condenseline_pressure.read_value() > 900 and self.still_pressure.read_value() > 10):
return Retry
else:
self.turbopump.write_target(1)
return self.wait_for_condense_line_pressure
def initialize_circulation_valves(self):
return True
@status_code(BUSY, 'circulate state')
def circulate(self):
"""Zirkuliert die Mischung."""
return self.initialize_circulation_valves()
@status_code(BUSY, 'remove state')
def remove(self):
"""Entfernt die Mischung."""
if self.init:
self.condenseline_valve.write_target(0)
self.dump_valve.write_target(1)
self.start_time = self.now
self.init = False
return Retry
if self.turbopump is not None:
self.turbopump.write_target(0)
if (self.now - self.start_time < 300 or self.turbopump.read_speed() > 60):
return Retry
self.circuitshort_valve.write_target(1)
if self.turbopump is not None:
if self.still_pressure.read_value() > 20:
return Retry
self.turbopump.write_target(1)
if self.still_pressure.read_value() > 1e-4:
return Retry
self.circuitshort_valve.write_target(0)
self.dump_valve.write_target(0)
if self.compressor is not None:
self.compressor.write_target(0)
for valve in self.remove_closed_valves:
valve.write_target(0)
self.circulate_pump.write_target(0)
return Finish
class DIL5(Dilution):
MV10 = Attached()
MV13 = Attached()
MV8 = Attached()
MVB = Attached()
MV2 = Attached()
MV1 = Attached()
MV3a = Attached()
MV3b = Attached()
GV1 = Attached()
MV14 = Attached()
MV12 = Attached()
MV11 = Attached()
MV9 = Attached()
GV2 = Attached()
def earlyInit(self):
self.circulate_closed_valves = [self.condense_valve, self.dump_valve, self.circuitshort_valve, self.MV10, self.MV13, self.MV8, self.MVB, self.MV2]
self.circulate_open_valves = [self.MV11, self.circulate_pump, self.GV2, self.V5, self.compressor, self.condenseline_valve, self.MV1, self.MV3a, self.MV3b, self.GV1, self.MV9, self.MV14]
self.condense_closed_valves = [self.MV10, self.MV13, self.MV8, self.MVB, self.MV2]
self.condense_open_valves = [self.MV1, self.MV3a, self.MV3b, self.GV1, self.MV9, self.MV14, self.MV12, self.MV11]
super().earlyInit()
def initialize_condense_valves(self):
#Anfangszustand der Ventile überprüfen
for valve in self.condense_open_valves:
if valve.read_value() == 0:
self.stop_machine()
raise ImpossibleError(f'valve {valve.name} must be open')
for valve in self.condense_closed_valves:
if valve.read_value == 1:
self.stop_machine()
return ImpossibleError(f'valve {valve.name} must be closed')
def initialize_circulation_valves(self):
#Anfangszustand der Ventile überprüfen
self.value = Targetstates.CIRCULATE
for valve in self.circulate_closed_valves:
if (valve.read_value() == 1):
self.stop_machine()
raise ImpossibleError(f'valve {valve.name} must be open')
for valve in self.circulate_open_valves:
if (valve.read_value() == 0):
valve.write_target(1)
self.stop_machine()
raise ImpossibleError(f'valve {valve.name} must be open')