/************************************************************************** * niche_evolution.cpp * Source code for the model described in Ashby et al "Competing species * leave many potential niches unfilled". Each row of the file * "niche_evolution.txt" records the n-dimensional coordinates of each * species in niche space at a given evolutionary time point, padded by * NaNs. For example, in 2-dimensional niche space, column 1 is the * x-coordinate of species 1, column 2 is the y-coordinate of species 1, * column 3 is the x-coordiante of species 2, and so on. * * The authors accept no responsibility or liability for any loss or damage * arising from the use of this code. * * Author: Ben Ashby * 09/10/2016 * v1.0 *************************************************************************/ #include #include #include #include #include #include /* Model parameter values */ #define ADDITIVE 1 /* Model version: 1=additive, 0=multiplicative*/ #define DIMENSIONS 2 /* Dimensionality of niche space */ #define NICHE_DIMENSION_SIZE 7.0 /* Length of each niche axis */ #define MAXSPECIES 100 /* Maximum number of species allowed */ #define R_GRAD 0.0 /* Rate at which r falls away from its maximum */ #define K_GRAD 0.0 /* Rate at which K falls away from its maximum */ #define EPSILON1 0.1 /* Maximum mutation distance in each dimension*/ #define EPSILON2 0.05 /* Extinction threshold */ /* Solver parameter values */ #define NEVOL 1000 /* Number of iterations (evolutionary timesteps) */ #define MAXTIME 1e4 /* Duration for ecological dynamics */ #define MAXSTEPS 1e6 /* Maximum number of steps for ODE solver */ #define INTERVAL 1000 /* Check if the system is close to equilibrium */ #define EQTOL 1e-4 /* Equilibrium tolerance (ODE) */ #define EPS 1e-6 /* ODE solver tolerance */ #define TINY 1e-6 /* Constant value for solver */ #define PI 3.141592653589793 /* Pi */ /************************************* * Function prototypes *************************************/ void my_rungkut(double *x, double **positions, double *r, double *K, int species); void rkqs(double *y, double *dydt, double **alpha, double *r, double *K, int species, double *h1, double *hnext, double *yscale); void rkck(double *y, double *dydt, double **alpha, double *r, double *K, int species, double *yout, double *yerr, double h1); void ddt(double *x, double *dev, double **alpha, double *r, double *K, int species); double FMAX(double l, double r); double FMIN(double l, double r); double** array_maker(int rows, int cols); void free_array(double **array, int rows); double uniform_rng(); double normal_rng(); double my_mod(double x, double y); /*************************************** * Main function ***************************************/ int main (int argc, char* argv[]) { double **positions, pop_size[MAXSPECIES], r[MAXSPECIES], K[MAXSPECIES]; double prog_gap, next_prog, d; int i, j, k, species, species_count; char filename[100]; /* Random seed */ srand(time(0)); prog_gap = 0.05; /* Create output file */ sprintf(filename, "niche_evolution.txt"); std::cout << "filename:" << filename << "\n"; std::ifstream infile(filename); if(infile.good()) { std::cout << "File already exists, deleting file...\n"; remove(filename); } std::ofstream out(filename, std::ios::app); if (!out){ std::cout << "Cannot create file\n"; exit(1); } /* Initial conditions */ positions = array_maker(MAXSPECIES, DIMENSIONS); for (i=0; i=next_prog){ std::cout << "Progress = " << 100*next_prog << "%\n"; next_prog+=prog_gap; } /* Call ODE solver */ my_rungkut(pop_size, positions, r, K, species); /* Remove species that are below the extinction threshold */ species_count = 0; for (j=0; j=EPSILON2){ if(species_count=MAXSPECIES) break; d = 0; for(k=0;k=MAXSPECIES) break; for(k=0;k0){ /* Additive version */ alpha[i][j] = 0; for (k=0;k(MAXTIME-t)){ hnext[0] = MAXTIME-t; h[0] = MAXTIME-t; t=MAXTIME; } else{ h[0] = hnext[0]; t+=h[0]; } if(t==MAXTIME) { exitflag=1; } /* This is where your equations are first solved */ ddt(x, dxdt, alpha, r, K, species); /* Adjust the step size to maintain accuracy */ for (i=0;inextcheck){ exitflag = 1; for (i=0; iEQTOL){ exitflag = 0; break; } } if(exitflag==1){ break; } nextcheck+=INTERVAL; for(i=0;i1e4) { printf("Unknown error with adaptive step size!\n"); exit(EXIT_FAILURE); } htemp= 0.9*(*h1)*pow(errmax, -0.25); *h1= (*h1>=0.0 ? FMAX(htemp, 0.1*(*h1)) : FMIN(htemp, 0.1*(*h1))); } if(errmax > 1.89E-4) { *hnext= 0.9*(*h1)*pow(errmax, -0.2); } else { *hnext= 5.0*(*h1); } for(i=0;ir)return l; else return r; } double FMIN(double l, double r) { if(l=y){ return x-NICHE_DIMENSION_SIZE; } else if(x<0){ return x+NICHE_DIMENSION_SIZE; } else { return x; } }