{-# LANGUAGE RecordWildCards #-}
module Epidemic.BirthDeathSamplingCatastropheOccurrence
( configuration
, allEvents
, observedEvents
) where
import Epidemic.Types.Population
import Epidemic.Types.Events
import Epidemic.Types.Parameter
import Data.Maybe (fromJust)
import qualified Data.Vector as V
import qualified Data.Vector.Generic as G
import System.Random.MWC
import System.Random.MWC.Distributions (categorical, exponential, bernoulli)
import Epidemic
import Epidemic.Utility
data BDSCOParameters
= BDSCOParameters Rate Rate Rate (Timed Probability) Rate
instance ModelParameters BDSCOParameters where
rNaught (BDSCOParameters birthRate deathRate samplingRate _ occurrenceRate) _ =
Just $ birthRate / (deathRate + samplingRate + occurrenceRate)
eventRate (BDSCOParameters birthRate deathRate samplingRate _ occurrenceRate) _ =
Just $ birthRate + deathRate + samplingRate + occurrenceRate
birthProb (BDSCOParameters birthRate deathRate samplingRate _ occurrenceRate) _ =
Just $ birthRate / (birthRate + deathRate + samplingRate + occurrenceRate)
newtype BDSCOPopulation =
BDSCOPopulation People
deriving (Show)
instance Population BDSCOPopulation where
susceptiblePeople _ = Nothing
infectiousPeople (BDSCOPopulation people) = Just people
removedPeople _ = Nothing
isInfected (BDSCOPopulation (People people)) = not $ V.null people
configuration :: Time
-> (Rate,Rate,Rate,[(Time,Probability)],Rate)
-> Maybe (SimulationConfiguration BDSCOParameters BDSCOPopulation)
configuration maxTime (birthRate, deathRate, samplingRate, catastropheProb, occurrenceRate) = do
catastropheTimedProb <- asTimed catastropheProb
let bdscoParams =
BDSCOParameters
birthRate
deathRate
samplingRate
catastropheTimedProb
occurrenceRate
(seedPerson, newId) = newPerson initialIdentifier
bdscoPop = BDSCOPopulation (People $ V.singleton seedPerson)
in Just $ SimulationConfiguration bdscoParams bdscoPop newId maxTime
randomBdscoEvent ::
BDSCOParameters
-> Time
-> BDSCOPopulation
-> Integer
-> GenIO
-> IO (Time, EpidemicEvent, BDSCOPopulation, Integer)
randomBdscoEvent params@(BDSCOParameters br dr sr catastInfo occr) currTime currPop@(BDSCOPopulation (People people)) currId gen =
let netEventRate = fromJust $ eventRate params currTime
eventWeights = V.fromList [br, dr, sr, occr]
in
do delay <- exponential (fromIntegral (V.length people) * netEventRate) gen
nextEventTime <- pure $ currTime + delay
if noScheduledEvent currTime nextEventTime catastInfo
then do eventIx <- categorical eventWeights gen
(selectedPerson, unselectedPeople) <- randomPerson people gen
return $ case eventIx of
0 -> let (birthedPerson, newId) = newPerson currId
event = Infection nextEventTime selectedPerson birthedPerson
in ( nextEventTime
, event
, BDSCOPopulation (People $ V.cons birthedPerson people)
, newId)
1 -> (nextEventTime, Removal nextEventTime selectedPerson, BDSCOPopulation (People unselectedPeople), currId)
2 -> (nextEventTime, Sampling nextEventTime selectedPerson, BDSCOPopulation (People unselectedPeople), currId)
3 -> (nextEventTime, Occurrence nextEventTime selectedPerson, BDSCOPopulation (People unselectedPeople), currId)
_ -> error "no birth, death, sampling, occurrence event selected."
else let (Just (catastTime,catastProb)) = firstScheduled currTime catastInfo
in do (catastEvent,postCatastPop) <- randomCatastropheEvent (catastTime,catastProb) currPop gen
return (catastTime,catastEvent,postCatastPop,currId)
randomCatastropheEvent :: (Time,Probability)
-> BDSCOPopulation
-> GenIO
-> IO (EpidemicEvent,BDSCOPopulation)
randomCatastropheEvent (catastTime, rhoProb) (BDSCOPopulation (People currPeople)) gen = do
rhoBernoullis <- G.replicateM (V.length currPeople) (bernoulli rhoProb gen)
let filterZip predicate a b = fst . V.unzip . V.filter predicate $ V.zip a b
sampledPeople = filterZip snd currPeople rhoBernoullis
unsampledPeople = filterZip (not . snd) currPeople rhoBernoullis
in return
( Catastrophe catastTime (People sampledPeople)
, BDSCOPopulation (People unsampledPeople))
allEvents ::
BDSCOParameters
-> Time
-> (Time, [EpidemicEvent], BDSCOPopulation, Integer)
-> GenIO
-> IO (Time, [EpidemicEvent], BDSCOPopulation, Integer)
allEvents rates maxTime currState@(currTime, currEvents, currPop, currId) gen =
if isInfected currPop
then do
(newTime, event, newPop, newId) <-
randomBdscoEvent rates currTime currPop currId gen
if newTime < maxTime
then allEvents
rates
maxTime
(newTime, event : currEvents, newPop, newId)
gen
else return currState
else return currState
observedEvents :: [EpidemicEvent]
-> [EpidemicEvent]
observedEvents events = sort $ occurrenceEvents ++ sampleTreeEvents''
where
occurrenceEvents = filter isNonReconTreeObservation events
sampleTreeEvents'' =
sampleTreeEvents . sampleTree $ transmissionTree events (Person 1)