changeset 59:892cf703be62 draft

Uploaded
author greg
date Wed, 21 Nov 2018 11:42:37 -0500
parents 2194155309f4
children 393085589438
files insect_phenology_model.R insect_phenology_model.xml utils.R
diffstat 3 files changed, 271 insertions(+), 256 deletions(-) [+]
line wrap: on
line diff
--- a/insect_phenology_model.R	Fri Nov 09 13:05:31 2018 -0500
+++ b/insect_phenology_model.R	Wed Nov 21 11:42:37 2018 -0500
@@ -250,63 +250,51 @@
     return(mortality.probability)
 }
 
-#mortality.egg = function(temperature, adj=0) {
-#    # If no input from adjustment, default
-#    # value is 0 (data from Nielsen, 2008).
-#    T.mortality = c(15, 17, 20, 25, 27, 30, 33, 35);
-#    egg.mortality = c(50, 2, 1, 0, 0, 0, 5, 100);
-#    # Calculates slopes and intercepts for lines.
-#    slopes = NULL;
-#    intercepts = NULL;
-#    for (i in 1:length(T.mortality)) {
-#        slopes[i] = (egg.mortality[i+1] - egg.mortality[i]) / (T.mortality[i+1] - T.mortality[i]);
-#        intercepts[i] = -slopes[i] * T.mortality[i] + egg.mortality[i];
-#    }
-#    # Calculates mortality based on temperature.
-#    mortality.probability = NULL;
-#    for (j in 1:length(temperature)) {
-#        mortality.probability[j] = if(temperature[j] <= T.mortality[2]) {
-#                           temperature[j] * slopes[1] + intercepts[1];
-#                       } else if (temperature[j] > T.mortality[2] && temperature[j] <= T.mortality[3]) {
-#                           temperature[j] * slopes[2] + intercepts[2];
-#                       } else if (temperature[j] > T.mortality[3] && temperature[j] <= T.mortality[4]) {
-#                           temperature[j] * slopes[3] + intercepts[3];
-#                       } else if (temperature[j] > T.mortality[4] && temperature[j] <= T.mortality[5]) {
-#                           temperature[j] * slopes[4] + intercepts[4];
-#                       } else if (temperature[j] > T.mortality[5] && temperature[j] <= T.mortality[6]) {
-#                           temperature[j] * slopes[5] + intercepts[5];
-#                       } else if (temperature[j] > T.mortality[6] && temperature[j] <= T.mortality[7]) {
-#                           temperature[j] * slopes[6] + intercepts[6];
-#                       } else if (temperature[j] > T.mortality[7]) {
-#                           temperature[j] * slopes[7] + intercepts[7];
-#                       }
-#        # If mortality > 100, make it equal to 100.
-#        mortality.probability[mortality.probability>100] = 100;
-#        # If mortality <0, make equal to 0.
-#        mortality.probability[mortality.probability<0] = 0;
-#    }
-#    # Make mortality adjustments based on adj parameter.
-#    mortality.probability = (100 - mortality.probability) * adj + mortality.probability;
-#    # if mortality > 100, make it equal to 100.
-#    mortality.probability[mortality.probability>100] = 100;
-#    # If mortality <0, make equal to 0.
-#    mortality.probability[mortality.probability<0] = 0;
-#    # Change percent to proportion.
-#    mortality.probability = mortality.probability / 100;
-#    return(mortality.probability)
-#}
-
-mortality.egg = function(temperature) {
-    if (temperature < 12.7) {
-        mortality.probability = 0.8;
+mortality.egg = function(temperature, adj=0) {
+    # If no input from adjustment, default
+    # value is 0 (data from Nielsen, 2008).
+    T.mortality = c(15, 17, 20, 25, 27, 30, 33, 35);
+    egg.mortality = c(50, 2, 1, 0, 0, 0, 5, 100);
+    # Calculates slopes and intercepts for lines.
+    slopes = NULL;
+    intercepts = NULL;
+    for (i in 1:length(T.mortality)) {
+        slopes[i] = (egg.mortality[i+1] - egg.mortality[i]) / (T.mortality[i+1] - T.mortality[i]);
+        intercepts[i] = -slopes[i] * T.mortality[i] + egg.mortality[i];
     }
-    else {
-        mortality.probability = 0.8 - temperature / 40.0;
-        if (mortality.probability < 0) {
-            mortality.probability = 0.01;
-        }
+    # Calculates mortality based on temperature.
+    mortality.probability = NULL;
+    for (j in 1:length(temperature)) {
+        mortality.probability[j] = if(temperature[j] <= T.mortality[2]) {
+                           temperature[j] * slopes[1] + intercepts[1];
+                       } else if (temperature[j] > T.mortality[2] && temperature[j] <= T.mortality[3]) {
+                           temperature[j] * slopes[2] + intercepts[2];
+                       } else if (temperature[j] > T.mortality[3] && temperature[j] <= T.mortality[4]) {
+                           temperature[j] * slopes[3] + intercepts[3];
+                       } else if (temperature[j] > T.mortality[4] && temperature[j] <= T.mortality[5]) {
+                           temperature[j] * slopes[4] + intercepts[4];
+                       } else if (temperature[j] > T.mortality[5] && temperature[j] <= T.mortality[6]) {
+                           temperature[j] * slopes[5] + intercepts[5];
+                       } else if (temperature[j] > T.mortality[6] && temperature[j] <= T.mortality[7]) {
+                           temperature[j] * slopes[6] + intercepts[6];
+                       } else if (temperature[j] > T.mortality[7]) {
+                           temperature[j] * slopes[7] + intercepts[7];
+                       }
+        # If mortality > 100, make it equal to 100.
+        mortality.probability[mortality.probability>100] = 100;
+        # If mortality <0, make equal to 0.
+        mortality.probability[mortality.probability<0] = 0;
     }
+    # Make mortality adjustments based on adj parameter.
+    mortality.probability = (100 - mortality.probability) * adj + mortality.probability;
+    # if mortality > 100, make it equal to 100.
+    mortality.probability[mortality.probability>100] = 100;
+    # If mortality <0, make equal to 0.
+    mortality.probability[mortality.probability<0] = 0;
+    # Change percent to proportion.
+    mortality.probability = mortality.probability / 100;
     return(mortality.probability)
+}
 
 mortality.nymph = function(temperature) {
     if (temperature < 12.7) {
@@ -614,10 +602,6 @@
     cat("Number of days in year: ", num_days, "\n");
 }
 
-# Get the ticks date labels for plots.
-ticks_and_labels = get_x_axis_ticks_and_labels(temperature_data_frame, prepend_end_doy_norm, append_start_doy_norm);
-ticks = c(unlist(ticks_and_labels[1]));
-date_labels = c(unlist(ticks_and_labels[2]));
 # All latitude values are the same, so get the value for plots from the first row.
 latitude = temperature_data_frame$LATITUDE[1];
 
@@ -756,6 +740,7 @@
 # Total population.
 population.replications = matrix(rep(0, total_days*opt$replications), ncol=opt$replications);
 
+doy_zero_insects = NULL;
 # Process replications.
 for (current_replication in 1:opt$replications) {
     # Start with the user-defined number of insects per replication.
@@ -856,218 +841,225 @@
         # Newborn.
         birth.vector = NULL;
         # All individuals.
-        for (i in 1:num_insects) {
-            # Individual record.
-            vector.individual = vector.matrix[i,];
-            # Adjustment for late season mortality rate (still alive?).
-            if (latitude < 40.0) {
-                post.mortality = 1;
-                day.kill = 300;
-            }
-            else {
-                post.mortality = 2;
-                day.kill = 250;
-            }
-            if (vector.individual[2] == 0) {
-                # Egg.
-                #death.probability = opt$egg_mortality * mortality.egg(mean.temp, adj=opt$egg_mortality);
-                death.probability = opt$egg_mortality * mortality.egg(mean.temp);
-            }
-            else if (vector.individual[2] == 1 | vector.individual[2] == 2) {
-                # Nymph.
-                death.probability = opt$nymph_mortality * mortality.nymph(mean.temp);
-            }
-            else if (vector.individual[2] == 3 | vector.individual[2] == 4 | vector.individual[2] == 5) {
-                # Adult.
-                if (doy < day.kill) {
-                    death.probability = opt$adult_mortality * mortality.adult(mean.temp);
+        if (num_insects > 0) {
+            for (i in 1:num_insects) {
+                # Individual record.
+                vector.individual = vector.matrix[i,];
+                # Adjustment for late season mortality rate (still alive?).
+                if (latitude < 40.0) {
+                    post.mortality = 1;
+                    day.kill = 300;
+                }
+                else {
+                    post.mortality = 2;
+                    day.kill = 250;
+                }
+                if (vector.individual[2] == 0) {
+                    # Egg.
+                    death.probability = opt$egg_mortality * mortality.egg(mean.temp, adj=opt$egg_mortality);
+                }
+                else if (vector.individual[2] == 1 | vector.individual[2] == 2) {
+                    # Nymph.
+                    death.probability = opt$nymph_mortality * mortality.nymph(mean.temp);
+                }
+                else if (vector.individual[2] == 3 | vector.individual[2] == 4 | vector.individual[2] == 5) {
+                    # Adult.
+                    if (doy < day.kill) {
+                        death.probability = opt$adult_mortality * mortality.adult(mean.temp);
+                    }
+                    else {
+                        # Increase adult mortality after fall equinox.
+                        death.probability = opt$adult_mortality * post.mortality * mortality.adult(mean.temp);
+                    }
+                }
+                # Dependent on temperature and life stage?
+                u.d = runif(1);
+                if (u.d < death.probability) {
+                    death.vector = c(death.vector, i);
                 }
                 else {
-                    # Increase adult mortality after fall equinox.
-                    death.probability = opt$adult_mortality * post.mortality * mortality.adult(mean.temp);
-                }
-            }
-            # Dependent on temperature and life stage?
-            u.d = runif(1);
-            if (u.d < death.probability) {
-                death.vector = c(death.vector, i);
-            }
-            else {
-                # End of diapause.
-                if (vector.individual[1] == 0 && vector.individual[2] == 3) {
-                    # Overwintering adult (pre-vittelogenic).
-                    if (photoperiod > opt$photoperiod && vector.individual[3] > 68 && doy < 180) {
-                        # Add 68C to become fully reproductively matured.
-                        # Transfer to vittelogenic.
-                        vector.individual = c(0, 4, 0, 0, 0);
-                        vector.matrix[i,] = vector.individual;
+                    # End of diapause.
+                    if (vector.individual[1] == 0 && vector.individual[2] == 3) {
+                        # Overwintering adult (pre-vittelogenic).
+                        if (photoperiod > opt$photoperiod && vector.individual[3] > 68 && doy < 180) {
+                            # Add 68C to become fully reproductively matured.
+                            # Transfer to vittelogenic.
+                            vector.individual = c(0, 4, 0, 0, 0);
+                            vector.matrix[i,] = vector.individual;
+                        }
+                        else {
+                            # Add average temperature for current day.
+                            vector.individual[3] = vector.individual[3] + averages.temp;
+                            # Add 1 day in current stage.
+                            vector.individual[4] = vector.individual[4] + 1;
+                            vector.matrix[i,] = vector.individual;
+                        }
                     }
-                    else {
-                        # Add average temperature for current day.
-                        vector.individual[3] = vector.individual[3] + averages.temp;
-                        # Add 1 day in current stage.
-                        vector.individual[4] = vector.individual[4] + 1;
-                        vector.matrix[i,] = vector.individual;
+                    if (vector.individual[1] != 0 && vector.individual[2] == 3) {
+                        # Not overwintering adult (pre-vittelogenic).
+                        current.gen = vector.individual[1];
+                        if (vector.individual[3] > 68) {
+                            # Add 68C to become fully reproductively matured.
+                            # Transfer to vittelogenic.
+                            vector.individual = c(current.gen, 4, 0, 0, 0);
+                            vector.matrix[i,] = vector.individual;
+                        }
+                        else {
+                            # Add average temperature for current day.
+                            vector.individual[3] = vector.individual[3] + averages.temp;
+                            # Add 1 day in current stage.
+                            vector.individual[4] = vector.individual[4] + 1;
+                            vector.matrix[i,] = vector.individual;
+                        }
                     }
-                }
-                if (vector.individual[1] != 0 && vector.individual[2] == 3) {
-                    # Not overwintering adult (pre-vittelogenic).
-                    current.gen = vector.individual[1];
-                    if (vector.individual[3] > 68) {
-                        # Add 68C to become fully reproductively matured.
-                        # Transfer to vittelogenic.
-                        vector.individual = c(current.gen, 4, 0, 0, 0);
-                        vector.matrix[i,] = vector.individual;
-                    }
-                    else {
+                    # Oviposition -- where population dynamics comes from.
+                    if (vector.individual[2] == 4 && vector.individual[1] == 0 && mean.temp > 10) {
+                        # Vittelogenic stage, overwintering generation.
+                        if (vector.individual[4] == 0) {
+                            # Just turned in vittelogenic stage.
+                            num_insects.birth = round(runif(1, 2 + opt$min_clutch_size, 8 + opt$max_clutch_size));
+                        }
+                        else {
+                            # Daily probability of birth.
+                            p.birth = opt$oviposition * 0.01;
+                            u1 = runif(1);
+                            if (u1 < p.birth) {
+                                num_insects.birth = round(runif(1, 2, 8));
+                            }
+                        }
                         # Add average temperature for current day.
                         vector.individual[3] = vector.individual[3] + averages.temp;
                         # Add 1 day in current stage.
                         vector.individual[4] = vector.individual[4] + 1;
                         vector.matrix[i,] = vector.individual;
-                    }
-                }
-                # Oviposition -- where population dynamics comes from.
-                if (vector.individual[2] == 4 && vector.individual[1] == 0 && mean.temp > 10) {
-                    # Vittelogenic stage, overwintering generation.
-                    if (vector.individual[4] == 0) {
-                        # Just turned in vittelogenic stage.
-                        num_insects.birth = round(runif(1, 2 + opt$min_clutch_size, 8 + opt$max_clutch_size));
-                    }
-                    else {
-                        # Daily probability of birth.
-                        p.birth = opt$oviposition * 0.01;
-                        u1 = runif(1);
-                        if (u1 < p.birth) {
-                            num_insects.birth = round(runif(1, 2, 8));
+                        if (num_insects.birth > 0) {
+                            # Add new birth -- might be in different generations.
+                            new.gen = vector.individual[1] + 1;
+                            # Egg profile.
+                            new.individual = c(new.gen, 0, 0, 0, 0);
+                            new.vector = rep(new.individual, num_insects.birth);
+                            # Update batch of egg profile.
+                            new.vector = t(matrix(new.vector, nrow=5));
+                            # Group with total eggs laid in that day.
+                            birth.vector = rbind(birth.vector, new.vector);
                         }
                     }
-                    # Add average temperature for current day.
-                    vector.individual[3] = vector.individual[3] + averages.temp;
-                    # Add 1 day in current stage.
-                    vector.individual[4] = vector.individual[4] + 1;
-                    vector.matrix[i,] = vector.individual;
-                    if (num_insects.birth > 0) {
-                        # Add new birth -- might be in different generations.
-                        new.gen = vector.individual[1] + 1;
-                        # Egg profile.
-                        new.individual = c(new.gen, 0, 0, 0, 0);
-                        new.vector = rep(new.individual, num_insects.birth);
-                        # Update batch of egg profile.
-                        new.vector = t(matrix(new.vector, nrow=5));
-                        # Group with total eggs laid in that day.
-                        birth.vector = rbind(birth.vector, new.vector);
-                    }
-                }
-                # Oviposition -- for generation 1.
-                if (vector.individual[2] == 4 && vector.individual[1] == 1 && mean.temp > 12.5 && doy < 222) {
-                    # Vittelogenic stage, 1st generation
-                    if (vector.individual[4] == 0) {
-                        # Just turned in vittelogenic stage.
-                        num_insects.birth = round(runif(1, 2+opt$min_clutch_size, 8+opt$max_clutch_size));
-                    }
-                    else {
-                        # Daily probability of birth.
-                        p.birth = opt$oviposition * 0.01;
-                        u1 = runif(1);
-                        if (u1 < p.birth) {
-                            num_insects.birth = round(runif(1, 2, 8));
+                    # Oviposition -- for generation 1.
+                    if (vector.individual[2] == 4 && vector.individual[1] == 1 && mean.temp > 12.5 && doy < 222) {
+                        # Vittelogenic stage, 1st generation
+                        if (vector.individual[4] == 0) {
+                            # Just turned in vittelogenic stage.
+                            num_insects.birth = round(runif(1, 2+opt$min_clutch_size, 8+opt$max_clutch_size));
+                        }
+                        else {
+                            # Daily probability of birth.
+                            p.birth = opt$oviposition * 0.01;
+                            u1 = runif(1);
+                            if (u1 < p.birth) {
+                                num_insects.birth = round(runif(1, 2, 8));
+                            }
+                        }
+                        # Add average temperature for current day.
+                        vector.individual[3] = vector.individual[3] + averages.temp;
+                        # Add 1 day in current stage.
+                        vector.individual[4] = vector.individual[4] + 1;
+                        vector.matrix[i,] = vector.individual;
+                        if (num_insects.birth > 0) {
+                            # Add new birth -- might be in different generations.
+                            new.gen = vector.individual[1] + 1;
+                            # Egg profile.
+                            new.individual = c(new.gen, 0, 0, 0, 0);
+                            new.vector = rep(new.individual, num_insects.birth);
+                            # Update batch of egg profile.
+                            new.vector = t(matrix(new.vector, nrow=5));
+                            # Group with total eggs laid in that day.
+                            birth.vector = rbind(birth.vector, new.vector);
                         }
                     }
-                    # Add average temperature for current day.
-                    vector.individual[3] = vector.individual[3] + averages.temp;
-                    # Add 1 day in current stage.
-                    vector.individual[4] = vector.individual[4] + 1;
-                    vector.matrix[i,] = vector.individual;
-                    if (num_insects.birth > 0) {
-                        # Add new birth -- might be in different generations.
-                        new.gen = vector.individual[1] + 1;
-                        # Egg profile.
-                        new.individual = c(new.gen, 0, 0, 0, 0);
-                        new.vector = rep(new.individual, num_insects.birth);
-                        # Update batch of egg profile.
-                        new.vector = t(matrix(new.vector, nrow=5));
-                        # Group with total eggs laid in that day.
-                        birth.vector = rbind(birth.vector, new.vector);
-                    }
-                }
-                # Egg to young nymph.
-                if (vector.individual[2] == 0) {
-                    # Add average temperature for current day.
-                    vector.individual[3] = vector.individual[3] + averages.temp;
-                    if (vector.individual[3] >= (68+opt$young_nymph_accumulation)) {
-                        # From egg to young nymph, degree-days requirement met.
-                        current.gen = vector.individual[1];
-                        # Transfer to young nymph stage.
-                        vector.individual = c(current.gen, 1, 0, 0, 0);
-                    }
-                    else {
-                        # Add 1 day in current stage.
-                        vector.individual[4] = vector.individual[4] + 1;
+                    # Egg to young nymph.
+                    if (vector.individual[2] == 0) {
+                        # Add average temperature for current day.
+                        vector.individual[3] = vector.individual[3] + averages.temp;
+                        if (vector.individual[3] >= (68+opt$young_nymph_accumulation)) {
+                            # From egg to young nymph, degree-days requirement met.
+                            current.gen = vector.individual[1];
+                            # Transfer to young nymph stage.
+                            vector.individual = c(current.gen, 1, 0, 0, 0);
+                        }
+                        else {
+                            # Add 1 day in current stage.
+                            vector.individual[4] = vector.individual[4] + 1;
+                        }
+                        vector.matrix[i,] = vector.individual;
                     }
-                    vector.matrix[i,] = vector.individual;
-                }
-                # Young nymph to old nymph.
-                if (vector.individual[2] == 1) {
-                    # Add average temperature for current day.
-                    vector.individual[3] = vector.individual[3] + averages.temp;
-                    if (vector.individual[3] >= (250+opt$old_nymph_accumulation)) {
-                        # From young to old nymph, degree_days requirement met.
-                        current.gen = vector.individual[1];
-                        # Transfer to old nym stage.
-                        vector.individual = c(current.gen, 2, 0, 0, 0);
-                        if (photoperiod < opt$photoperiod && doy > 180) {
-                            vector.individual[5] = 1;
-                        } # Prepare for diapausing.
-                    }
-                    else {
-                        # Add 1 day in current stage.
-                        vector.individual[4] = vector.individual[4] + 1;
-                    }
-                    vector.matrix[i,] = vector.individual;
-                }
-                # Old nymph to adult: pre-vittelogenic or diapausing?
-                if (vector.individual[2] == 2) {
-                    # Add average temperature for current day.
-                    vector.individual[3] = vector.individual[3] + averages.temp;
-                    if (vector.individual[3] >= (200+opt$adult_accumulation)) {
-                        # From old to adult, degree_days requirement met.
-                        current.gen = vector.individual[1];
-                        if (vector.individual[5] == 0) {
-                            # Previttelogenic.
-                            vector.individual = c(current.gen, 3, 0, 0, 0);
+                    # Young nymph to old nymph.
+                    if (vector.individual[2] == 1) {
+                        # Add average temperature for current day.
+                        vector.individual[3] = vector.individual[3] + averages.temp;
+                        if (vector.individual[3] >= (250+opt$old_nymph_accumulation)) {
+                            # From young to old nymph, degree_days requirement met.
+                            current.gen = vector.individual[1];
+                            # Transfer to old nym stage.
+                            vector.individual = c(current.gen, 2, 0, 0, 0);
+                            if (photoperiod < opt$photoperiod && doy > 180) {
+                                vector.individual[5] = 1;
+                            } # Prepare for diapausing.
                         }
                         else {
-                            # Diapausing.
-                            vector.individual = c(current.gen, 5, 0, 0, 1);
+                            # Add 1 day in current stage.
+                            vector.individual[4] = vector.individual[4] + 1;
                         }
+                        vector.matrix[i,] = vector.individual;
                     }
-                    else {
-                        # Add 1 day in current stage.
-                        vector.individual[4] = vector.individual[4] + 1;
+                    # Old nymph to adult: pre-vittelogenic or diapausing?
+                    if (vector.individual[2] == 2) {
+                        # Add average temperature for current day.
+                        vector.individual[3] = vector.individual[3] + averages.temp;
+                        if (vector.individual[3] >= (200+opt$adult_accumulation)) {
+                            # From old to adult, degree_days requirement met.
+                            current.gen = vector.individual[1];
+                            if (vector.individual[5] == 0) {
+                                # Previttelogenic.
+                                vector.individual = c(current.gen, 3, 0, 0, 0);
+                            }
+                            else {
+                                # Diapausing.
+                                vector.individual = c(current.gen, 5, 0, 0, 1);
+                            }
+                        }
+                        else {
+                            # Add 1 day in current stage.
+                            vector.individual[4] = vector.individual[4] + 1;
+                        }
+                        vector.matrix[i,] = vector.individual;
                     }
-                    vector.matrix[i,] = vector.individual;
-                }
-                # Growing of diapausing adult (unimportant, but still necessary).
-                if (vector.individual[2] == 5) {
-                    vector.individual[3] = vector.individual[3] + averages.temp;
-                    vector.individual[4] = vector.individual[4] + 1;
-                    vector.matrix[i,] = vector.individual;
-                }
-            } # Else if it is still alive.
-        } # End of the individual bug loop.
+                    # Growing of diapausing adult (unimportant, but still necessary).
+                    if (vector.individual[2] == 5) {
+                        vector.individual[3] = vector.individual[3] + averages.temp;
+                        vector.individual[4] = vector.individual[4] + 1;
+                        vector.matrix[i,] = vector.individual;
+                    }
+                } # Else if it is still alive.
+            } # End of the individual bug loop.
 
-        # Number of deaths.
-        num_insects.death = length(death.vector);
-        if (num_insects.death > 0) {
-            # Remove record of dead.
-            vector.matrix = vector.matrix[-death.vector,];
+            # Number of deaths.
+            num_insects.death = length(death.vector);
+            if (num_insects.death > 0) {
+                # Remove record of dead.
+                vector.matrix = vector.matrix[-death.vector,];
+            }
+            # Number of births.
+            num_insects.newborn = length(birth.vector[,1]);
+            vector.matrix = rbind(vector.matrix, birth.vector);
+            # Update population size for the next day.
+            num_insects = num_insects - num_insects.death + num_insects.newborn;
+        } else {
+            if (is.null(doy_zero_insects)) {
+                # Only set the doy for zero insects if
+                # it has not yet been set.
+                doy_zero_insects = doy;
+            }
         }
-        # Number of births.
-        num_insects.newborn = length(birth.vector[,1]);
-        vector.matrix = rbind(vector.matrix, birth.vector);
-        # Update population size for the next day.
-        num_insects = num_insects - num_insects.death + num_insects.newborn;
 
         # Aggregate results by day.  Due to multiple transpose calls
         # on vector.matrix above, the columns of vector.matrix
@@ -1547,7 +1539,12 @@
     write.csv(temperature_data_frame_F2, file=file_path, row.names=F);
 }
 
+# Get the ticks date labels for plots.
+ticks_and_labels = get_x_axis_ticks_and_labels(temperature_data_frame, prepend_end_doy_norm=prepend_end_doy_norm, append_start_doy_norm=append_start_doy_norm, date_interval=FALSE, doy_zero_insects=doy_zero_insects);
+ticks = c(unlist(ticks_and_labels[1]));
+date_labels = c(unlist(ticks_and_labels[2]));
 total_days_vector = c(1:dim(temperature_data_frame)[1]);
+
 if (plot_generations_separately) {
     for (life_stage in life_stages) {
         if (life_stage == "Egg") {
--- a/insect_phenology_model.xml	Fri Nov 09 13:05:31 2018 -0500
+++ b/insect_phenology_model.xml	Wed Nov 21 11:42:37 2018 -0500
@@ -82,7 +82,7 @@
             <option value="BMSB" selected="True">Brown Marmorated Stink Bug</option>
         </param>
         <param name="replications" type="integer" value="10" min="2" label="Number of replications"/>
-        <param name="insects_per_replication" type="integer" value="1000" min="1" label="Number of insects with which to start each replication"/>
+        <param name="insects_per_replication" type="integer" value="1000" min="100" label="Number of insects with which to start each replication"/>
         <param name="photoperiod" type="float" value="13.5" min="0" label="Critical photoperiod for diapause induction/termination"/>
         <param name="egg_mortality" type="float" value="1" min="0" max="1" label="Adjustment rate for egg mortality" help="Floating point value between 0 and 1"/>
         <param name="nymph_mortality" type="float" value="1" min="0" label="Adjustment rate for nymph mortality"/>
--- a/utils.R	Fri Nov 09 13:05:31 2018 -0500
+++ b/utils.R	Wed Nov 21 11:42:37 2018 -0500
@@ -96,7 +96,7 @@
     }
 }
 
-get_x_axis_ticks_and_labels = function(temperature_data_frame, prepend_end_doy_norm=0, append_start_doy_norm=0, date_interval=FALSE) {
+get_x_axis_ticks_and_labels = function(temperature_data_frame, prepend_end_doy_norm=0, append_start_doy_norm=0, date_interval=FALSE, doy_zero_insects=NULL) {
     # Generate a list of ticks and labels for plotting the x axis.
     if (prepend_end_doy_norm > 0) {
         prepend_end_norm_row = which(temperature_data_frame$DOY==prepend_end_doy_norm);
@@ -108,6 +108,11 @@
     } else {
         append_start_norm_row = 0;
     }
+    if (is.null(doy_zero_insects)) {
+        zero_insects_row = 0;
+    } else {
+        zero_insects_row = which(temperature_data_frame$DOY==doy_zero_insects);
+    }
     num_rows = dim(temperature_data_frame)[1];
     tick_labels = list();
     ticks = list();
@@ -130,11 +135,24 @@
         doy = as.integer(temperature_data_frame$DOY[i]);
         # We're plotting the entire year, so ticks will
         # occur on Sundays and the first of each month.
-        if (i == prepend_end_norm_row) {
+        if (i == zero_insects_row) {
+            # Add a tick for the day on which the number of insects
+            # per replication is 0.
+            label_str = "Number insects is 0";
+            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep);
+            ticks[tick_index] = i;
+            if (date_interval) {
+                # Append the day to label_str
+                tick_labels[tick_index] = paste(label_str, day, sep=" ");
+            } else {
+                tick_labels[tick_index] = label_str;
+            }
+            last_tick = i;
+        } else if (i == prepend_end_norm_row) {
             # Add a tick for the end of the 30 year normnals data
             # that was prepended to the year-to-date data.
             label_str = "End prepended 30 year normals";
-            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep)
+            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep);
             ticks[tick_index] = i;
             if (date_interval) {
                 # Append the day to label_str
@@ -147,7 +165,7 @@
             # Add a tick for the start of the 30 year normnals data
             # that was appended to the year-to-date data.
             label_str = "Start appended 30 year normals";
-            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep)
+            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep);
             ticks[tick_index] = i;
             if (!identical(current_month_label, month_label)) {
                 # Append the month to label_str.
@@ -163,7 +181,7 @@
         } else if (i==num_rows) {
             # Add a tick for the last day of the year.
             label_str = "";
-            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep)
+            tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep);
             ticks[tick_index] = i;
             if (!identical(current_month_label, month_label)) {
                 # Append the month to label_str.
@@ -178,7 +196,7 @@
         } else {
             if (!identical(current_month_label, month_label)) {
                 # Add a tick for the month.
-                tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep)
+                tick_index = get_tick_index(i, last_tick, ticks, tick_labels, tick_sep);
                 ticks[tick_index] = i;
                 if (date_interval) {
                     # Append the day to the month.