1 static char help[] = "Demonstrates Conway's Game of Life using a 2d DMDA.\n\n"; 2 3 /* 4 At each step in time, the following transitions occur: 5 6 Any live cell with fewer than two live neighbours dies, as if by underpopulation. 7 Any live cell with two or three live neighbours lives on to the next generation. 8 Any live cell with more than three live neighbours dies, as if by overpopulation. 9 Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. 10 11 https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life 12 */ 13 14 #include <petscdm.h> 15 #include <petscdmda.h> 16 17 static const int GLIDER[3][3] = { 18 {0, 1, 0}, 19 {0, 1, 1}, 20 {1, 0, 1} 21 }; 22 23 int main(int argc,char **argv) 24 { 25 PetscErrorCode ierr; 26 DM da; 27 PetscViewer viewer; 28 Vec Xlocal, Xglobal; 29 PetscInt glider_loc[2] = {10, 20}, blinker_loc[2] = {20, 10}, two, steps = 100, viz_interval = 1; 30 PetscInt check_step_alive = -1, check_step_dead = -1; 31 PetscBool has_glider, has_blinker; 32 33 ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr; 34 ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Conway's Game of Life","");CHKERRQ(ierr); 35 { 36 ierr = PetscOptionsIntArray("-glider","Coordinate at which to center a glider",NULL,glider_loc,(two=2,&two),&has_glider);CHKERRQ(ierr); 37 ierr = PetscOptionsIntArray("-blinker","Coordinate at which to center a blinker",NULL,blinker_loc,(two=2,&two),&has_blinker);CHKERRQ(ierr); 38 ierr = PetscOptionsInt("-steps","Number of steps to take",NULL,steps,&steps,NULL);CHKERRQ(ierr); 39 ierr = PetscOptionsInt("-viz_interval","Vizualization interval",NULL,viz_interval,&viz_interval,NULL);CHKERRQ(ierr); 40 ierr = PetscOptionsInt("-check_step_alive","Step on which to check that the simulation is alive",NULL,check_step_alive,&check_step_alive,NULL);CHKERRQ(ierr); 41 ierr = PetscOptionsInt("-check_step_dead","Step on which to check that the simulation is dead",NULL,check_step_dead,&check_step_dead,NULL);CHKERRQ(ierr); 42 } 43 ierr = PetscOptionsEnd();CHKERRQ(ierr); 44 45 ierr = PetscViewerDrawOpen(PETSC_COMM_WORLD,NULL,"Life",PETSC_DECIDE,PETSC_DECIDE,1000,1000,&viewer);CHKERRQ(ierr); 46 47 /* Create distributed array and get vectors */ 48 ierr = DMDACreate2d(PETSC_COMM_WORLD,DM_BOUNDARY_PERIODIC,DM_BOUNDARY_PERIODIC,DMDA_STENCIL_BOX,30,30,PETSC_DECIDE,PETSC_DECIDE,1,1,NULL,NULL,&da);CHKERRQ(ierr); 49 ierr = DMSetFromOptions(da);CHKERRQ(ierr); 50 ierr = DMSetUp(da);CHKERRQ(ierr); 51 ierr = DMCreateLocalVector(da,&Xlocal);CHKERRQ(ierr); 52 ierr = DMCreateGlobalVector(da,&Xglobal);CHKERRQ(ierr); 53 54 { /* Initialize */ 55 DMDALocalInfo info; 56 PetscScalar **x; 57 PetscInt i,j; 58 59 ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr); 60 ierr = DMDAVecGetArray(da, Xlocal, &x);CHKERRQ(ierr); 61 for (j=info.ys; j<info.ys+info.ym; j++) { 62 for (i=info.xs; i<info.xs+info.xm; i++) { 63 if (has_glider && i == glider_loc[0] && j == glider_loc[1]) { 64 PetscInt ii,jj; 65 for (ii=-1; ii<=1; ii++) 66 for (jj=-1; jj<=1; jj++) 67 x[j+jj][i+ii] = GLIDER[1-jj][ii+1]; 68 } 69 if (has_blinker && i == blinker_loc[0] && j == blinker_loc[1]) { 70 x[j-1][i] = 1; 71 x[j][i] = 1; 72 x[j+1][i] = 1; 73 } 74 } 75 } 76 ierr = DMDAVecRestoreArray(da, Xlocal, &x);CHKERRQ(ierr); 77 ierr = DMLocalToGlobal(da, Xlocal, ADD_VALUES, Xglobal);CHKERRQ(ierr); 78 } 79 80 /* View the initial condition */ 81 ierr = VecView(Xglobal, viewer);CHKERRQ(ierr); 82 83 { /* Play */ 84 PetscInt step; 85 86 for (step=0; step<steps; step++) { 87 const PetscScalar **x; 88 PetscScalar **y; 89 DMDALocalInfo info; 90 PetscInt i,j; 91 92 ierr = DMGlobalToLocal(da, Xglobal, INSERT_VALUES, Xlocal);CHKERRQ(ierr); 93 ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr); 94 ierr = DMDAVecGetArrayRead(da, Xlocal, &x);CHKERRQ(ierr); 95 ierr = DMDAVecGetArrayWrite(da, Xglobal, &y);CHKERRQ(ierr); 96 for (j=info.ys; j<info.ys+info.ym; j++) { 97 for (i=info.xs; i<info.xs+info.xm; i++) { 98 PetscInt live_neighbors = 0; 99 live_neighbors += PetscRealPart(x[j-1][i-1]) > 0; 100 live_neighbors += PetscRealPart(x[j-1][i]) > 0; 101 live_neighbors += PetscRealPart(x[j-1][i+1]) > 0; 102 live_neighbors += PetscRealPart(x[j][i-1]) > 0; 103 live_neighbors += PetscRealPart(x[j][i+1]) > 0; 104 live_neighbors += PetscRealPart(x[j+1][i-1]) > 0; 105 live_neighbors += PetscRealPart(x[j+1][i]) > 0; 106 live_neighbors += PetscRealPart(x[j+1][i+1]) > 0; 107 if (PetscRealPart(x[j][i]) > 0) { /* Live cell */ 108 switch (live_neighbors) { 109 case 2: 110 case 3: 111 y[j][i] = 1; /* Survive */ 112 break; 113 default: 114 y[j][i] = 0; /* Death */ 115 } 116 } else { /* Dead cell */ 117 if (live_neighbors == 3) y[j][i] = 1; /* Birth */ 118 else y[j][i] = 0; 119 } 120 } 121 } 122 ierr = DMDAVecRestoreArrayRead(da, Xlocal, &x);CHKERRQ(ierr); 123 ierr = DMDAVecRestoreArrayWrite(da, Xglobal, &y);CHKERRQ(ierr); 124 if (step == check_step_alive || step == check_step_dead) { 125 PetscScalar sum; 126 ierr = VecSum(Xglobal, &sum);CHKERRQ(ierr); 127 if (PetscAbsScalar(sum) > 0.1) { 128 if (step == check_step_dead) { 129 ierr = PetscPrintf(PETSC_COMM_WORLD,"Simulation alive at step %D\n",step);CHKERRQ(ierr); 130 } 131 } else if (step == check_step_alive) { 132 ierr = PetscPrintf(PETSC_COMM_WORLD,"Simulation dead at step %D\n",step);CHKERRQ(ierr); 133 } 134 } 135 if (step % viz_interval == 0) { 136 ierr = VecView(Xglobal, viewer);CHKERRQ(ierr); 137 } 138 } 139 } 140 141 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); 142 ierr = VecDestroy(&Xglobal);CHKERRQ(ierr); 143 ierr = VecDestroy(&Xlocal);CHKERRQ(ierr); 144 ierr = DMDestroy(&da);CHKERRQ(ierr); 145 ierr = PetscFinalize(); 146 return ierr; 147 } 148 149 150 /*TEST 151 152 test: 153 requires: x 154 nsize: 2 155 args: -glider 5,6 -blinker 12,12 -steps 35 -check_step_alive 31 -check_step_dead 32 -da_grid_x 20 -da_grid_y 20 -nox 156 157 TEST*/ 158