Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <mpi.h>
#include "simulation.h"
#define ELECTRON_HEAD '@'
#define ELECTRON_TAIL '~'
#define WIRE '#'
void wireworld_step(world_t *world, size_t i_start, size_t bx, size_t by);
void do_simulation(world_t *world, size_t n_generations)
{
const size_t nx = world->local_size[0];
const size_t ny = world->local_size[1];
const size_t DOWN = nx+2; // (+2 ... for halo cells)
const size_t i_leftupper = 1 + DOWN;
const size_t i_rightupper = nx + DOWN;
const size_t i_leftlower = 1 + ny*DOWN;
size_t g;
char *tmp;
const int counts[] = {1, 1, 1, 1, 1, 1, 1, 1};
const MPI_Aint displs[] = {0, 0, 0, 0, 0, 0, 0, 0};
const transfer_t *transfer = &world->transfer;
MPI_Request request;
for(g = 0; g < n_generations; g++) {
tmp = world->cells_prev;
world->cells_prev = world->cells_next;
world->cells_next = tmp;
// Start halo exchange
MPI_Ineighbor_alltoallw(
world->cells_prev, counts, displs, transfer->send_types,
world->cells_prev, counts, displs, transfer->recv_types,
transfer->graph_comm, &request
);
// Compute inner region
wireworld_step(world, i_leftupper+1+DOWN, nx-2, ny-2);
// Finish halo exchange
MPI_Wait(&request, MPI_STATUS_IGNORE);
// Compute boundary regions
wireworld_step(world, i_leftupper, nx, 1); // upper
wireworld_step(world, i_leftlower, nx, 1); // lower
wireworld_step(world, i_leftupper+DOWN, 1, ny-2); // left
wireworld_step(world, i_rightupper+DOWN, 1, ny-2); // right
/* Blocking variant:
MPI_Neighbor_alltoallw(
world->cells_prev, counts, displs, transfer->send_types,
world->cells_prev, counts, displs, transfer->recv_types,
transfer->graph_comm
);
wireworld_step(world, i_leftupper, nx, ny);
*/
}
}
void wireworld_step(world_t *world, size_t i_start, size_t bx, size_t by)
{
const size_t L = -1, R = 1;
const size_t D = world->local_size[0]+2; // (+2 ... for halo cells)
const size_t U = -D;
size_t x, y, i;
int nheads;
char *prev = world->cells_prev;
char *next = world->cells_next;
for(y = 0; y < by; y++) {
i = i_start;
for(x = 0; x < bx; x++) {
switch(prev[i]) {
// Electron heads become electron tails.
case ELECTRON_HEAD: next[i] = ELECTRON_TAIL; break;
// Electron tails become copper.
case ELECTRON_TAIL: next[i] = WIRE; break;
// New electron head replacing copper,
// if 1 or 2 electron heads are in neighborhood.
case WIRE:
nheads =
(prev[i+L+U] == ELECTRON_HEAD) +
(prev[i +U] == ELECTRON_HEAD) +
(prev[i+R+U] == ELECTRON_HEAD) +
(prev[i+L ] == ELECTRON_HEAD) +
(prev[i+R ] == ELECTRON_HEAD) +
(prev[i+L+D] == ELECTRON_HEAD) +
(prev[i +D] == ELECTRON_HEAD) +
(prev[i+R+D] == ELECTRON_HEAD);
if(nheads == 1 || nheads == 2) {
next[i] = ELECTRON_HEAD;
} else {
next[i] = WIRE;
}
break;
default: break;
}
i++;
}
i_start += D;
}
}