4d605a7780c236603ea7e2bcc1265ec89484b71d
[charm.git] / examples / charm++ / jacobi2d / jacobi2d.C
1 #include "jacobi2d.decl.h"
2
3 /*
4 Jacobi iteratoin with a 2D Array.
5
6 Demonstrates 2d dense char array creation and use.  This code computes
7 the steady state heat distribution of a 2d plate using the jacobi
8 iteration:
9
10 while new_temp != temp
11   //next temperature is average of surrounding temperatures 
12   new_temp(x,y) = (temp(x-1,y)+temp(x+1,y)+temp(x,y-1)+temp(x,y+1))/4
13   temp(x,y) = new_temp(x,y)
14 end
15
16 Every temp(x,y) is a chare in this sample application.  The main chare
17 sends a notice to all the nodes in our simulation telling them to
18 exchange information.  After each node is done updating it's
19 temperature, it sends a message back the error as the difference
20 between temp and new_temp.  Main quits driving the iterations when the
21 error has been minimized below some threshold.
22
23 */
24
25 CProxy_Main mainProxy;
26 int num_rows;
27 int num_cols;
28
29 //allowed variation between temp and new_temp
30 float epsilon=1./1000;
31
32 //temperatures on the various boundries
33 float left = 1;
34 float top = 1;
35 float bottom = 0;
36 float right = 0;
37
38
39 class Main : public CBase_Main
40 {
41 public:
42     int receive_count;
43     CProxy_Jacobi array;
44     int num_chares;
45
46     Main(CkArgMsg* m) {
47         mainProxy = thisProxy;
48
49         //Allow the user to adjust the size of the grid at runtime
50         num_cols = 5;
51         if (m->argc == 2) {
52             num_cols = atoi(m->argv[1]);
53         }
54         delete m;
55         
56         num_rows = num_cols;
57
58         CkPrintf("Running Jacobi on %d processors with (%d,%d) elements\n",
59                  CkNumPes(), num_rows, num_cols);
60
61         array = CProxy_Jacobi::ckNew(num_rows, num_cols);
62
63         //save the total number of worker chares we have in this simulation
64         num_chares = num_rows*num_cols;
65
66         //Start the computation
67         receive_count = num_chares;
68         array.begin_iteration();
69     }
70
71     float max_error;
72
73     void report_error(int row, int col, float error) {
74         CkPrintf("[main] (%d, %d) error=%g\n", row, col, error);
75
76         if ((receive_count == num_chares)
77             ||
78             (fabs(error) > max_error)
79             ) {
80             max_error = fabs(error);
81         }
82
83         receive_count--;
84         if (0 == receive_count) {
85             if (max_error < epsilon) {
86                 CkPrintf("All done\n");
87                 CkExit();
88             } else {
89                 CkPrintf("[main] error = %g, starting new iteration.\n", max_error);
90                 receive_count=num_chares;
91                 array.begin_iteration();
92             }
93         }
94     }
95 };
96     
97 class Jacobi: public CBase_Jacobi {
98 public:
99     float temperature;
100     float update;
101     int messages_due;
102
103     Jacobi() {
104         temperature = 0;
105         messages_due = 4;
106     }
107
108     Jacobi(CkMigrateMessage* m) {}
109
110     //added for array migration
111     void pup(PUP::er &p){
112         p | temperature;
113         p | update;
114         p | messages_due;
115     }
116
117     void begin_iteration(void) {
118         /* messages_due should not be assigned here because it is not guaranteed
119          * that all elements' function "begin_iteration" are called before the
120          * function "receive_neighbor". Otherwise, the "messages_due" is messed up.
121          * For example, assuming the 2D array is of size 2*2. Then the array element(0,1)
122          * would send its data to element(1,1) and element(0,0) according to the sequence
123          * of calling "receive_neighbor" in this function. If element(1,1)'s "receive_neighbor"
124          * is called before its "begin_iteration" call and the "message_due" is reset
125          * in the "begin_iteration" function, then the "messages_due" of element(1,1) would be 
126          * messed up. Because one of 4 messages that element(1,1) needs to receive is already
127          * posted, the "messages_due" should not be reset, otherwise element(1,1) would think
128          * there's still one msg to receive and woudl not progress to the next iteration.
129          * The solution is to initialize the value in Jacobi's constructor and reset it
130          * before doing the next iteration (in the check_done_iteration function) --Chao Mei
131          */
132 //      messages_due = 4;
133         update = 0;
134
135         //enforce the boundary conditions.  Nodes on an edge shouldn't
136         //send messages to non-existant chares.
137         if (thisIndex.x == 0) {
138             update += top;
139             messages_due--;
140         } else {
141             thisProxy(thisIndex.x-1, thisIndex.y).receive_neighbor(temperature);
142         }
143
144         if (thisIndex.x == num_rows-1) {
145             update += bottom;
146             messages_due--;
147         } else {
148             thisProxy(thisIndex.x+1, thisIndex.y).receive_neighbor(temperature);
149         }
150
151         if (thisIndex.y == 0) {
152             update += left;
153             messages_due--;
154         } else {
155             thisProxy(thisIndex.x, thisIndex.y-1).receive_neighbor(temperature);
156         }
157
158         if (thisIndex.y == num_cols-1) {
159             update += right;
160             messages_due--;
161         } else {
162             thisProxy(thisIndex.x, thisIndex.y+1).receive_neighbor(temperature);
163         }
164
165         //check to see if we still need messages.
166         check_done_iteration();
167     }
168
169     void receive_neighbor(float new_temperature) {
170         update += new_temperature;
171         messages_due--;
172         check_done_iteration();
173     }
174
175     void check_done_iteration() {
176         if (messages_due == 0) {
177             update /= 4;
178             float error = update-temperature;
179             temperature = update;
180             messages_due = 4;
181             mainProxy.report_error(thisIndex.x, thisIndex.y, error);
182         }
183     }
184  
185 };
186
187 #include "jacobi2d.def.h"