If the files are not present, then run their corresponding scripts and generate them.
The corresponding R Markdown scripts associated with these files can be found on RPub:
setwd("/Users/Nick/mysisModeling") #Locate ourselves in the computer.
#Check for solar data
if(!file.exists("data/light_day_moon_hour.csv")){ source("dataGen/solarData.r") }
#Check for thermocline data
if(!file.exists("data/Depth_Thermocline_Hour.csv")){ source("dataGen/thermoclineLevels.r") }
#Mysocline data
if(!file.exists("data/mysocline_hour.csv")){ source("dataGen/depthModel.r") }
#Mysocline data
if(!file.exists("data/FoodAvail_Hour.csv")){ source("dataGen/foodAvailability.r") }
#Read in the data now.
depthData = read.csv("data/mysocline_hour.csv")$x
foodCurve = read.csv("data/FoodAvail_hour.csv")
foodAvail = foodCurve$foodAvail
foodVar = foodCurve$variability
I have chosen to use the S4 object oriented programing style. The details are minor but more info can be found here.
This basically is a digital mysis that simplistically holds a couple of peices of information and upon which the model will act.
setClass("mysis",
representation(
energy = "numeric", # The energy reserves are a numeric value
migrating = "logical", # If mysis is migrating is a logical value
alive = "logical", # Alive still?
depth = "numeric"),
prototype(
energy = 0, # The default instantiated mysis starts with zero energy...
migrating = FALSE, # and not migrating...
alive = TRUE, # alive
depth = 100), # and at the bottom.
)
#Set the show method, basically how we want the program to display the info about the mysis on calling.
setMethod("show", "mysis",
function(object){
if (object@alive){
print(object@energy)
print(object@migrating)
print(object@depth)
} else {
print("dead")
}
})
Real quick we need to make a model for decisions to migrate based upon condition:
The form of this model is a logistic curve: \[f(x) = \frac{1}{1 + e^{-k(x - m)}}\] Where \(k\) is an indicator of steepness, and \(m\) is the midepoint of the curve.
migrationProb = function(condition){ #I am choosing to leave the random roll outside of script for continuity, could be changed
m = 120 #value of curve midpoint
k = 0.03 #steepness of curve
x = condition
dist = 1/(1 + exp(-k* (x - m)))
return(1 - dist)
}
This is a stochastic model, meaning it utilizes randomness to simulate the real world.
The function of the decision tree is such:
rewardUnits = .68
setGeneric( "nextTime", function(object, ...){standardGeneric("nextTime")})
setMethod("nextTime","mysis",
function(object, foodAvail, foodVar, time){ #Takes in the mysis object and the ratio of food quality at a given time.
#Run the draws:
migrationDraw = runif(1) #random number between 0 and 1, this will be used for the migration decision
migrationDraw_2 = runif(1) #draw for second migration decision, this time compared to logistic curve
predationDraw = runif(1) #" " to see if killed by predation
#Lets set some constants real quick:
migrationCost = 21 #How many energy units the mysis use up migrating
migrationRisk = 0 #We don't really need to simulate predation.
stayRisk = 0
# migrationRisk = 0.0001 #Chance of being eaten if migrating
# stayRisk = 0.00001 #Chance of being eaten if they stay on the bottom
#Energy rewards:
migrationReward = rnorm(1, (rewardUnits*(1 + foodAvail)), foodVar)
stayReward = migrationReward * .2
threshold = 0.2 #Let's make sure that the benthic reward can never drop below a threshold.
if(stayReward < threshold){
stayReward = threshold
}
# migrationReward = rnorm(1,rewardUnits, foodVar)
# stayReward = rnorm(1,(rewardUnits * ( 1 - foodAvail)), foodVar)
#this makes the rewards responsive to conditions
sunset = 18 #hardcode sunset, fill this with real data later.
sunrise = 7
conditionCurve = migrationProb(object@energy)
if (object@energy <= 0){ #did the mysis starve?
object@alive = FALSE
}
#if the mysis is in good condition use standard migration chance, if bad use 1 - chance
if ((time %% 24 == sunset + 1)&&(object@alive)){
if (migrationDraw < foodAvail) {
object@migrating = migrationDraw_2 > conditionCurve
object@energy = object@energy - migrationCost
} else {
object@migrating = FALSE
}
} else if (time %% 24 == sunrise){ #bring them back down at sunrise.
object@migrating = FALSE
}
#Here is the decision tree:
if (object@alive){ #If the mysis is alive let's run the decision tree
if (object@migrating){
object@depth = depthData[time] #Grab the mysocline limit at this hour
if (predationDraw > migrationRisk){ #The mysis evades predation
object@energy = object@energy + migrationReward
} else { #Mysis is eaten
object@alive = FALSE
}
} else { #The mysis didn't migrate
object@depth = 100
if (predationDraw > stayRisk){ #The mysis evades predation
object@energy = object@energy + stayReward
} else { #Mysis is eaten
object@alive = FALSE
}
}
}
object} #Return the mysis
)
Now that the model is all set up can run it over a small subset of the eventual numbers (~10,000 mysids over 8,700 hours) and see what results we get.
mysids = NULL
numOfMysids = 50
for (i in 1:numOfMysids){
initialenergy = rnorm(1,150,25) #draw initial energy from normal dist centered at 30 with stdev of 5.
mysids = c(mysids, new("mysis", energy = initialenergy) )
}
… and now we can run the model on those mysids:
migrations = NULL
conditions = NULL
hours = 1:(24*365) #150 days
for (mysid in mysids){ #loop through the mysis
migration = NULL
condition = NULL
for (i in hours){
mysid = nextTime(mysid, foodAvail[i], foodVar[i] , i)
migration = c(migration, mysid@depth)
condition = c(condition, mysid@energy)
}
migrations = cbind(migrations, migration) # add to the object of migrations.
conditions = cbind(conditions, condition)
}
Let’s plot this small run to see what kind of behavior we are getting.
This obviously isn’t right.
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
We will set the food quality at 0.7
# #rewardUnits = 1
# foodAvail = 0.7
# foodVar = 0.3
# migrateVals = NULL
# stayVals = NULL
# for (i in 1:5000){
#
# # rnorm(1,rewardUnits, rewardUnits*stdMult)
# # stayReward = rnorm(1,(rewardUnits * ( 1 - foodAvail)), rewardUnits*stdMult)
# migrateVals = c(migrateVals, rnorm(1,rewardUnits, foodVar))
# stayVals = c(stayVals, rnorm(1,(rewardUnits * ( 1 - foodAvail)), foodVar ) )
# }
#
# par(mfrow=c(2,1))
# hist(migrateVals, main = "Migrate", xlim=c(-3,6))
# hist(stayVals, main = "Stay", xlim = c(-3,6))?
It would appear that we need to be a litle more ‘mean’ with our taking away of energy.