# new version modified Aug 2018.
#
# for next cooldown:
# - test offset feature (this is something like integral part in PI control)
# - reg is max(MagTop - 100, target)

proc makeN2cool {{temp "tcoil ta"} {topTemp "tcoil tc"}} {
  makeobject n2coolPar array logged
  n2coolPar makeitem temp $temp
  n2coolPar makeitem topTemp $topTemp
  n2coolPar makeitem state inactive
  n2coolPar makeitem istate 0

# date and hour when to finish (set to tomorrow at start)
  n2coolPar makeitem day [clock format [expr [clock seconds] + 24*3600] -format %d]
  n2coolPar makeitem time 6
  n2coolPar makeitem last 0
  n2coolPar makeitem target 85

  n2coolPar makeitem interval 600
  n2coolPar makeitem maxDif 100
# filtered temperature
  n2coolPar makeitem tfil 0
# regulation temperature
  n2coolPar makeitem reg 0
  n2coolPar makeitem offset 0
  n2coolPar makeitem prop 3

  obj_list makeitem n2coolPar "LN2 cooldown parameters"
  Layout n2cool

  makenv n2valve n2cool_ccu -controller _lnv -port ma15-ts:3004
}

proc n2coolLayout args {
  RadioGroup n2cool [result n2coolPar state]
  Label "LN2 cooldown (plug valve to CCU on MA15 rack)"
  NoNewline
  RadioButton inactive
  NoNewline
  RadioButton start
  Newline
  RadioButton opened
  NoNewline
  RadioButton closed
  Newline
  Tip "Name of bottom coil sensor temperature (MagBot)"
  Input "coil sensor" "n2coolPar temp"
  Tip "Name of top coil sensor temperature (MagTop)"
  Input "coil sensor" "n2coolPar topTemp"
  Input "coil sensor target" "n2coolPar target"
  Newline
  Tip "finish day \[day of month\]"
  Input "finish day" "n2coolPar day"
  Tip "finish hour \[decimal fractions possible\]"
  Input "finish hour" "n2coolPar time"
  Newline
  Tip "max. difference MagTop - MagBot"
  Input "max dif" "n2coolPar maxDif"
  Tip "regulation interval"
  Input "interval" "n2coolPar interval"
  Tip "Kelvin / min."
  Input "prop" "n2coolPar prop"
  Input "T_reg" "n2coolPar reg"
  Input "T_offset" "n2coolPar offset"
}

#
# Automatic N2 Precooling for Cryomagnets (tested for MA15 only)
#
#Typical usage:
# sicscron 1 n2cool
#
# the temperature of MagBot is regulated at the maximum of MagTop - maxDif and
# target
# Every 10 minutes (interval) the valve is opened and closed again
# it is closed again after a time proportional to the the difference between
# T_filtered and T_reg - offset. This time is calculated live from T_filtered.
# The valve is then kept closed until the next 10 min interval.
#
proc n2cool {{arg none}} {
  switch $arg {
    start {
      if {[result n2coolPar istate] != 0} {
        error "started already"
      }
      n2coolPar state start
      n2coolPar day [clock format [expr [clock seconds] + 24*3600] -format %d]
      n2coolPar last 0
      sicscron 1 n2cool
      return
    }
    inactive {
      clientput "close and finish"
      n2coolPar state inactive
      n2valve 2
      n2coolPar istate 0
      return
    }
    none { }
    default {
      clientput "ERROR: n2cool $arg not allowed"
      error stop
      return
    }
  }

  if {[result n2coolPar state] eq "inactive"} {
    error stop
  } 
  set now [clock seconds]

  set today [clock format $now -format %d]
  set seconds [expr $now - [clock scan 00:00]]
  if {$today == [result n2coolPar day] && $seconds/3600.0 > [result n2coolPar time]} {
    n2coolPar state inactive
    n2valve 2
    n2coolPar istate 0
    clientput "finished at [clock format $now]"
    error stop
  }

  set state [result n2coolPar state]
  set oldState $state
  set t [result [result n2coolPar temp]]
  set ttop [result [result n2coolPar topTemp]]
  set last [result n2coolPar last]

  set offset [result n2coolPar offset]
  set tfil [result n2coolPar tfil]
  set interval [result n2coolPar interval]
  set target [result n2coolPar target]
  set maxDif [result n2coolPar maxDif]
  set reg [format %.1f [expr max($ttop - $maxDif, $target)]]
  n2coolPar reg $reg
  set prop [result n2coolPar prop]
  if {$tfil == 0} {
    n2coolPar tfil $t
  } else {
    set w [expr 2.0 / $interval]
    set tfil [expr $tfil + ($t - $tfil) * $w]
    n2coolPar tfil $tfil
    if {$now > $last + $interval} {
      n2coolPar last $now
      if {$tfil > $reg - $offset} {
        n2valve 1
        n2coolPar state opened
clientput open
      } else {
        n2valve 0
        n2coolPar state closed
      }
    } elseif {$tfil < $reg + double($now - $last) / 60.0 * $prop - $offset} {
      if {[sctval /n2valve] != 0} {
        n2coolPar offset [expr 0.5 * ($offset + $tfil - $reg)]
  clientput close
        n2valve 0
        n2coolPar state closed
      }
    }
  }
  switch [result n2coolPar state] {
    opened {
      n2valve 1
      n2coolPar istate 1
    }
    closed - closedFast {
      n2coolPar istate 2
    }
    inactive {
      n2coolPar istate 0
      clientput "n2cool deactivated"
      error stop
    }
  }
  return
}

publishLazy n2cool
