# # Model Stem for PCA and PCA + continuous mode. # Note: operator error model will change parameters through a perl script. # # Copyright (C) Sriram Sankaranarayanan # University of Colorado, Boulder # Sriram Sankaranarayanan # Copyright (c) 2011-2012. All rights reserved. # 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 3 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, see . # # This model is distributed as is without any warranties explicit or implied. # The author and the University of Colorado are not responsible for any mistakes, # inconsistencies, or inaccuracies in this model. Use at your own risk. # #Simulation time step: do not change. param simTimeStep: num EQ 1.0; #volume in syringe param volInSyringe: num EQ 120.0; #ml #how many faults allowed per simulation. param maxFaults: num EQ 0.0; #what is the minimum time in a transient fault param minFaultTime: num EQ 4.0; #what is max time in a transient fault param maxFaultTime: num EQ 10.0; # Drug concentration. param drugConc: num EQ 20.0; # The possible pump modes: CONT_ONLY: continuous mode, CONT_PCA: continuous + pca, PCA_ONLY: pca only mode param pcaMode: enum IN {CONT_ONLY, CONT_PCA, PCA_ONLY} ; # cRate: continuous infusion rate param cRate: num EQ 0.3; # unit ml/min # pcaBolusRate: Rate at which PCA bolus is delivered param pcaBolusRate: num EQ 0.5; # unit ml/min # pcaBolusTime: Time for a bolus param pcaBolusTime: num EQ 2.0; # unit min. #pcaLockout: lockout time for PCA param pcaLockout: num EQ 6; # unit min #pcaLimit: limit for number of PCA requests/hr param pcaLimit: num EQ 5; # unit max requests/hr # some model consistency checks at the start assume defined (cRate) && defined(pcaBolusRate) && defined(pcaLockout) && defined(pcaLimit); component syringePump { # syringepump component # Pump states are as follows: # CONT_INFUSION: pump infusing in continuous mode # INFUSION_FAULT: fault (pump stopped) # PCA_INFUSION: pump is serving a PCA request from patient # VIAL_EMPTY: the vial is empty (equivalent to a fault) var curState: enum IN { CONT_INFUSION, INFUSION_FAULT, PCA_INFUSION, VIAL_EMPTY }; # State of the pump var vSyringe: num IN [0.0, 600.0]; # amount of drug in syringe nondet faultEvent: boolean; # fault event: non deterministically chosen at each time step nondet resetEvent: boolean; # reset event: if under fault, should we reset. Again this is nondeterministic. nondet pcaRequest: boolean; # pca request has arrived from user? non-deterministic at each time step. clock faultTimer IN [0,1000]; # fault timer: started when system is under fault var totFaults: num IN [0,10]; # totFaults: how many faults so far in the execution? var u: num IN [0.0, 100.0]; # u: output rate to patient. clock globTime IN [0.0,100.0]; # global time clock pcaTimer IN [0.0,100.0]; # how long have I been in pca mode clock lockoutTimer IN [0.0,100.0]; # how long since last pca request var nPCA: num; # number of PCA requests init ( curState == CONT_INFUSION && # start with continuous mode vSyringe == volInSyringe && # set volume in syringe faultTimer == 0.0 && # set fault timer totFaults == maxFaults && # total faults set to maxFaults parameter u == cRate && # u set to continuous infusion rate globTime == 0.0 && # global time is zero pcaTimer == 0.0 && # pca time is zero lockoutTimer == pcaLockout && # lockout timer has pcaLockout units nPCA == pcaLimit ); | curState == CONT_INFUSION -> [ # if current state is continous infusing | vSyringe > 0.0 -> { vSyringe := vSyringe - u * simTimeStep; } # and there is volume left, reduce volume by amt. infused | vSyringe <= 0.0 -> { vSyringe := 0.0; curState := VIAL_EMPTY; u := 0; faultTimer := 0.0; } # if no volume left, go to VIAL_EMPTY State | (vSyringe > 0.0 && faultEvent && totFaults > 0) -> # if volume left and fault and number of faults so far is less than max to simulate, { totFaults := totFaults - 1; # Reduce the number of allowed faults faultTimer := 0; # start the fault timer by reseting it. u := 0; vSyringe := vSyringe - u * simTimeStep; # update vSyringe but set drug output rate to 0 curState := INFUSION_FAULT; # enter INFUSION_FAULT state } # from continuous infusion -> PCA mode # 1. request arrives from user. # 2. pca mode is enabled in the initial setup. # 3. lockout timer has exceeded minimum lockout # 4. PCA requests are less than maximum allowed | (pcaRequest && (pcaMode == CONT_PCA || pcaMode == PCA_ONLY) && lockoutTimer >= pcaLockout && nPCA > 0) -> { curState := PCA_INFUSION; # current state is pca infusion pcaTimer := 0.0; # pca timer is reset to 0 vSyringe := vSyringe - u * simTimeStep; # volume in syringe is updated u := cRate + pcaBolusRate; # rate of drug delivery is updated nPCA := nPCA - 1; # number of pca requests is reduced } ] | curState == INFUSION_FAULT -> [ # In state infusion fault | ((resetEvent && faultTimer > minFaultTime) ||( faultTimer > maxFaultTime)) -> { # reset event arrives when fault time is between min and max fault time u := cRate; lockoutTimer := pcaLockout; curState := CONT_INFUSION; # go back to continuous mode } ] | curState == PCA_INFUSION -> [ # In state for pca infusion | (vSyringe > 0.0 && pcaTimer < pcaBolusTime) -> { vSyringe := vSyringe - u * simTimeStep; } | (vSyringe <= 0.0 && pcaTimer < pcaBolusTime) -> { vSyringe := 0.0; curState := VIAL_EMPTY; u := 0; faultTimer := 0.0; } | (pcaTimer >= pcaBolusTime && pcaTimer < pcaBolusTime + simTimeStep) -> { vSyringe := vSyringe - u * simTimeStep; u := cRate; curState := CONT_INFUSION; lockoutTimer := 0.0; } | (faultEvent && totFaults > 0 && pcaTimer < pcaBolusTime) -> { vSyringe := vSyringe - u * simTimeStep; totFaults := totFaults - 1; faultTimer := 0; u := 0; curState := INFUSION_FAULT; } ] | curState == VIAL_EMPTY -> [ | (faultTimer > minFaultTime && resetEvent && faultTimer <= maxFaultTime ) -> { vSyringe := volInSyringe; u := cRate; lockoutTimer := pcaLockout; curState := CONT_INFUSION; } ] }; component patient { # patient model # x1..x4 are four chambers in PK/PD model # x4 is the effect chamber whose conc. we care about. # variable u is inherited from component syringePump # all variables are global unless shadowed by a component. var x1: num; #ng/mL var x2: num ; # ng /mL var x3: num ; # ng /mL var x4: num ; # ng/mL init ( x1 == 0 && x2 == 0 && x3 == 0 && x4 == 0) ; | (0 == 0) -> { x1 := 0.36 * x1 + 0.18* x2 + 0.01 * x3 + 0.09 * drugConc * u; x2 := 0.08*x1 + 0.9 * x2 + 0.001 * x3 + 0.007 * drugConc * u; x3 := 0.001* x1 + 0.002 * x2 + x3 + 0.00008 * drugConc * u ; x4 := 0.35 * x1 + 0.08*x2 + 0.006 * x3+ 0.4 * x4 + 0.035* drugConc * u; } }; max x4 IN [0.0, 300.0] step 0.1 when totFaults == 0; end