|
1 |
| -/* |
2 |
| - Program to solve the two-dimensional Ising model using MPI. |
3 |
| - The coupling constant J = 1 |
4 |
| - Boltzmann's constant = 1 --> temperature has dimension energy |
5 |
| - The code needs an output file on the command line and the variables mcs, nspins, |
6 |
| - initial temp, final temp and temp step. |
7 |
| -*/ |
8 |
| - |
9 |
| -#include "mpi.h" |
10 |
| -#include <cmath> |
11 | 1 | #include <iostream>
|
12 |
| -#include <fstream> |
13 |
| -#include <iomanip> |
14 |
| -#include <cstdlib> |
15 |
| -#include <time.h> |
16 |
| -using namespace std; |
17 |
| - |
18 |
| -// output file |
19 |
| -ofstream ofile; |
20 | 2 |
|
21 |
| -// inline function for periodic boundary conditions |
22 |
| -inline int periodic(int i, int limit, int add) { |
23 |
| - return (i+limit+add) % (limit); |
24 |
| -} |
25 |
| -// Function to initialise energy and magnetization |
26 |
| -void initialize(int, int **, double&, double&); |
27 |
| -// The metropolis algorithm |
28 |
| -void Metropolis(int, long&, int **, double&, double&, double *); |
29 |
| -// prints to file the results of the calculations |
30 |
| -void output(int, int, double, double *, double); |
31 |
| -// Matrix memory allocation |
32 |
| -// allocate space for a matrix |
33 |
| -void **matrix(int, int, int); |
34 |
| -// free space for a matrix |
35 |
| -void free_matrix(void **); |
36 |
| -// ran2 for uniform deviates, initialize with negative seed. |
37 |
| -double ran2(long *); |
| 3 | +using namespace std; |
38 | 4 |
|
39 |
| -// Main program begins here |
40 |
| - |
41 |
| -int main(int argc, char* argv[]) |
| 5 | +int main() |
42 | 6 | {
|
43 |
| - char *outfilename; |
44 |
| - long idum; |
45 |
| - int **spin_matrix, n_spins, mcs, my_rank, numprocs; |
46 |
| - double w[17], average[5], total_average[5], |
47 |
| - initial_temp, final_temp, E, M, temp_step; |
48 |
| - double calculation_time; |
49 |
| - |
50 |
| - // MPI initializations |
51 |
| - MPI_Init (&argc, &argv); |
52 |
| - MPI_Comm_size (MPI_COMM_WORLD, &numprocs); |
53 |
| - MPI_Comm_rank (MPI_COMM_WORLD, &my_rank); |
54 |
| - if (my_rank == 0 && argc <= 1) { |
55 |
| - cout << "Bad Usage: " << argv[0] << |
56 |
| - " read output file" << endl; |
57 |
| - exit(1); |
58 |
| - } |
59 |
| - if (my_rank == 0 && argc > 1) { |
60 |
| - outfilename=argv[1]; |
61 |
| - ofile.open(outfilename); |
62 |
| - } |
63 |
| - n_spins = 100; mcs = 1000000; initial_temp = 2.25; final_temp = 2.31; temp_step = 0.005; |
64 |
| - |
65 |
| - /* |
66 |
| - Determine number of interval which are used by all processes |
67 |
| - myloop_begin gives the starting point on process my_rank |
68 |
| - myloop_end gives the end point for summation on process my_rank |
69 |
| - */ |
70 |
| - |
71 |
| - int no_intervalls = mcs/numprocs; |
72 |
| - int myloop_begin = my_rank*no_intervalls + 1; |
73 |
| - int myloop_end = (my_rank+1)*no_intervalls; |
74 |
| - if ( (my_rank == numprocs-1) &&( myloop_end < mcs) ) myloop_end = mcs; |
75 |
| - |
76 |
| - // broadcast to all nodes common variables |
77 |
| - MPI_Bcast (&n_spins, 1, MPI_INT, 0, MPI_COMM_WORLD); |
78 |
| - MPI_Bcast (&initial_temp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); |
79 |
| - MPI_Bcast (&final_temp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); |
80 |
| - MPI_Bcast (&temp_step, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); |
81 |
| - |
82 |
| - // Allocate memory for spin matrix |
83 |
| - spin_matrix = (int**) matrix(n_spins, n_spins, sizeof(int)); |
84 |
| - |
85 |
| - // every node has its own seed for the random numbers, this is important else |
86 |
| - // if one starts with the same seed, one ends with the same random numbers |
87 |
| - idum = -1-my_rank; // random starting point |
88 |
| - |
89 |
| - // Start Monte Carlo sampling by looping over T first |
90 |
| - for ( double temperature = initial_temp; temperature <= final_temp; temperature+=temp_step){ |
91 |
| - // initialize energy and magnetization |
92 |
| - E = M = 0.; |
93 |
| - |
94 |
| - // initialise array for expectation values |
95 |
| - initialize(n_spins, spin_matrix, E, M); |
96 |
| - |
97 |
| - // setup array for possible energy changes |
98 |
| - for( int de =-8; de <= 8; de++) w[de+8] = 0; |
99 |
| - for( int de =-8; de <= 8; de+=4) w[de+8] = exp(-de/temperature); |
100 |
| - for( int i = 0; i < 5; i++) average[i] = 0.; |
101 |
| - for( int i = 0; i < 5; i++) total_average[i] = 0.; |
102 |
| - |
103 |
| - // start Monte Carlo computation |
104 |
| - // Initialize calculation time |
105 |
| - clock_t start, finish; |
106 |
| - start = clock(); |
107 |
| - for (int cycles = myloop_begin; cycles <= myloop_end; cycles++){ |
108 |
| - Metropolis(n_spins, idum, spin_matrix, E, M, w); |
109 |
| - // update expectation values for local node |
110 |
| - average[0] += E; average[1] += E*E; |
111 |
| - average[2] += M; average[3] += M*M; average[4] += fabs(M); |
112 |
| - } |
113 |
| - finish = clock(); |
114 |
| - calculation_time = (finish - start)/(double)CLOCKS_PER_SEC; |
115 |
| - // Find total average |
116 |
| - for( int i =0; i < 5; i++){ |
117 |
| - MPI_Reduce(&average[i], &total_average[i], 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); |
118 |
| - } |
119 |
| - // print results |
120 |
| - if ( my_rank == 0) { |
121 |
| - output(n_spins, mcs, temperature, total_average, calculation_time); |
122 |
| - } |
123 |
| - } |
124 |
| - free_matrix((void **) spin_matrix); // free memory |
125 |
| - ofile.close(); // close output file |
126 |
| - // End MPI |
127 |
| - MPI_Finalize (); |
128 |
| - return 0; |
| 7 | + cout << "Hello World!" << endl; |
| 8 | + return 0; |
129 | 9 | }
|
130 | 10 |
|
131 |
| -// function to initialise energy, spin matrix and magnetization |
132 |
| -void initialize(int n_spins, int **spin_matrix, |
133 |
| - double& E, double& M) |
134 |
| -{ |
135 |
| - // setup spin matrix and intial magnetization |
136 |
| - for(int y =0; y < n_spins; y++) { |
137 |
| - for (int x= 0; x < n_spins; x++){ |
138 |
| - spin_matrix[y][x] = 1; // spin orientation for the ground state |
139 |
| - M += (double) spin_matrix[y][x]; |
140 |
| - } |
141 |
| - } |
142 |
| - // setup initial energy |
143 |
| - for(int y =0; y < n_spins; y++) { |
144 |
| - for (int x= 0; x < n_spins; x++){ |
145 |
| - E -= (double) spin_matrix[y][x]* |
146 |
| - (spin_matrix[periodic(y,n_spins,-1)][x] + |
147 |
| - spin_matrix[y][periodic(x,n_spins,-1)]); |
148 |
| - } |
149 |
| - } |
150 |
| -}// end function initialise |
151 |
| - |
152 |
| -void Metropolis(int n_spins, long& idum, int **spin_matrix, double& E, double&M, double *w) { |
153 |
| - // loop over all spins |
154 |
| - for(int y =0; y < n_spins; y++) { |
155 |
| - for (int x= 0; x < n_spins; x++){ |
156 |
| - int ix = (int) (ran2(&idum)*(double)n_spins); |
157 |
| - int iy = (int) (ran2(&idum)*(double)n_spins); |
158 |
| - int deltaE = 2*spin_matrix[iy][ix]* |
159 |
| - (spin_matrix[iy][periodic(ix,n_spins,-1)] + |
160 |
| - spin_matrix[periodic(iy,n_spins,-1)][ix] + |
161 |
| - spin_matrix[iy][periodic(ix,n_spins,1)] + |
162 |
| - spin_matrix[periodic(iy,n_spins,1)][ix]); |
163 |
| - if ( ran2(&idum) <= w[deltaE+8] ) { |
164 |
| - spin_matrix[iy][ix] *= -1; // flip one spin and accept new spin config |
165 |
| - M += (double) 2*spin_matrix[iy][ix]; |
166 |
| - E += (double) deltaE; |
167 |
| - } |
168 |
| - } |
169 |
| - } |
170 |
| -} // end of Metropolis sampling over spins |
171 |
| - |
172 |
| - |
173 |
| -void output(int n_spins, int mcs, double temperature, double *total_average, double compute_time) |
174 |
| -{ |
175 |
| - double norm = 1/((double) (mcs)); // divided by total number of cycles |
176 |
| - double Etotal_average = total_average[0]*norm; |
177 |
| - double E2total_average = total_average[1]*norm; |
178 |
| - double Mtotal_average = total_average[2]*norm; |
179 |
| - double M2total_average = total_average[3]*norm; |
180 |
| - double Mabstotal_average = total_average[4]*norm; |
181 |
| - // all expectation values are per spin, divide by 1/n_spins/n_spins |
182 |
| - double Evariance = (E2total_average- Etotal_average*Etotal_average)/n_spins/n_spins; |
183 |
| - double Mvariance = (M2total_average - Mabstotal_average*Mabstotal_average)/n_spins/n_spins; |
184 |
| - ofile << setiosflags(ios::showpoint | ios::uppercase); |
185 |
| - ofile << "Temperature: " << "Energy: " << "Heat capacity: " |
186 |
| - << "Magnetization: " << "Susceptibility: " << "abs(Magnetization): " |
187 |
| - << endl; |
188 |
| - ofile << setw(15) << setprecision(8) << temperature; |
189 |
| - ofile << setw(15) << setprecision(8) << Etotal_average/n_spins/n_spins; |
190 |
| - ofile << setw(15) << setprecision(8) << Evariance/temperature/temperature; |
191 |
| - ofile << setw(15) << setprecision(8) << Mtotal_average/n_spins/n_spins; |
192 |
| - ofile << setw(15) << setprecision(8) << Mvariance/temperature; |
193 |
| - ofile << setw(15) << setprecision(8) << Mabstotal_average/n_spins/n_spins; |
194 |
| - ofile << setw(15) << setprecision(8) << compute_time << endl; |
195 |
| -} // end output function |
196 |
| - |
197 |
| -/* |
198 |
| -** The function |
199 |
| -** ran2() |
200 |
| -** is a long periode (> 2 x 10^18) random number generator of |
201 |
| -** L'Ecuyer and Bays-Durham shuffle and added safeguards. |
202 |
| -** Call with idum a negative integer to initialize; thereafter, |
203 |
| -** do not alter idum between sucessive deviates in a |
204 |
| -** sequence. RNMX should approximate the largest floating point value |
205 |
| -** that is less than 1. |
206 |
| -** The function returns a uniform deviate between 0.0 and 1.0 |
207 |
| -** (exclusive of end-point values). |
208 |
| -*/ |
209 |
| - |
210 |
| -#define IM1 2147483563 |
211 |
| -#define IM2 2147483399 |
212 |
| -#define AM (1.0/IM1) |
213 |
| -#define IMM1 (IM1-1) |
214 |
| -#define IA1 40014 |
215 |
| -#define IA2 40692 |
216 |
| -#define IQ1 53668 |
217 |
| -#define IQ2 52774 |
218 |
| -#define IR1 12211 |
219 |
| -#define IR2 3791 |
220 |
| -#define NTAB 32 |
221 |
| -#define NDIV (1+IMM1/NTAB) |
222 |
| -#define EPS 1.2e-7 |
223 |
| -#define RNMX (1.0-EPS) |
224 |
| - |
225 |
| -double ran2(long *idum) |
226 |
| -{ |
227 |
| - int j; |
228 |
| - long k; |
229 |
| - static long idum2 = 123456789; |
230 |
| - static long iy=0; |
231 |
| - static long iv[NTAB]; |
232 |
| - double temp; |
233 |
| - |
234 |
| - if(*idum <= 0) { |
235 |
| - if(-(*idum) < 1) *idum = 1; |
236 |
| - else *idum = -(*idum); |
237 |
| - idum2 = (*idum); |
238 |
| - for(j = NTAB + 7; j >= 0; j--) { |
239 |
| - k = (*idum)/IQ1; |
240 |
| - *idum = IA1*(*idum - k*IQ1) - k*IR1; |
241 |
| - if(*idum < 0) *idum += IM1; |
242 |
| - if(j < NTAB) iv[j] = *idum; |
243 |
| - } |
244 |
| - iy=iv[0]; |
245 |
| - } |
246 |
| - k = (*idum)/IQ1; |
247 |
| - *idum = IA1*(*idum - k*IQ1) - k*IR1; |
248 |
| - if(*idum < 0) *idum += IM1; |
249 |
| - k = idum2/IQ2; |
250 |
| - idum2 = IA2*(idum2 - k*IQ2) - k*IR2; |
251 |
| - if(idum2 < 0) idum2 += IM2; |
252 |
| - j = iy/NDIV; |
253 |
| - iy = iv[j] - idum2; |
254 |
| - iv[j] = *idum; |
255 |
| - if(iy < 1) iy += IMM1; |
256 |
| - if((temp = AM*iy) > RNMX) return RNMX; |
257 |
| - else return temp; |
258 |
| -} |
259 |
| -#undef IM1 |
260 |
| -#undef IM2 |
261 |
| -#undef AM |
262 |
| -#undef IMM1 |
263 |
| -#undef IA1 |
264 |
| -#undef IA2 |
265 |
| -#undef IQ1 |
266 |
| -#undef IQ2 |
267 |
| -#undef IR1 |
268 |
| -#undef IR2 |
269 |
| -#undef NTAB |
270 |
| -#undef NDIV |
271 |
| -#undef EPS |
272 |
| -#undef RNMX |
273 |
| - |
274 |
| -// End: function ran2() |
275 |
| - |
276 |
| - |
277 |
| - /* |
278 |
| - * The function |
279 |
| - * void **matrix() |
280 |
| - * reserves dynamic memory for a two-dimensional matrix |
281 |
| - * using the C++ command new . No initialization of the elements. |
282 |
| - * Input data: |
283 |
| - * int row - number of rows |
284 |
| - * int col - number of columns |
285 |
| - * int num_bytes- number of bytes for each |
286 |
| - * element |
287 |
| - * Returns a void **pointer to the reserved memory location. |
288 |
| - */ |
289 |
| - |
290 |
| -void **matrix(int row, int col, int num_bytes) |
291 |
| - { |
292 |
| - int i, num; |
293 |
| - char **pointer, *ptr; |
294 |
| - |
295 |
| - pointer = new(nothrow) char* [row]; |
296 |
| - if(!pointer) { |
297 |
| - cout << "Exception handling: Memory allocation failed"; |
298 |
| - cout << " for "<< row << "row addresses !" << endl; |
299 |
| - return NULL; |
300 |
| - } |
301 |
| - i = (row * col * num_bytes)/sizeof(char); |
302 |
| - pointer[0] = new(nothrow) char [i]; |
303 |
| - if(!pointer[0]) { |
304 |
| - cout << "Exception handling: Memory allocation failed"; |
305 |
| - cout << " for address to " << i << " characters !" << endl; |
306 |
| - return NULL; |
307 |
| - } |
308 |
| - ptr = pointer[0]; |
309 |
| - num = col * num_bytes; |
310 |
| - for(i = 0; i < row; i++, ptr += num ) { |
311 |
| - pointer[i] = ptr; |
312 |
| - } |
313 |
| - |
314 |
| - return (void **)pointer; |
315 |
| - |
316 |
| - } // end: function void **matrix() |
317 |
| - |
318 |
| - /* |
319 |
| - * The function |
320 |
| - * void free_matrix() |
321 |
| - * releases the memory reserved by the function matrix() |
322 |
| - *for the two-dimensional matrix[][] |
323 |
| - * Input data: |
324 |
| - * void far **matr - pointer to the matrix |
325 |
| - */ |
326 |
| - |
327 |
| -void free_matrix(void **matr) |
328 |
| -{ |
329 |
| - |
330 |
| - delete [] (char *) matr[0]; |
331 |
| - delete [] matr; |
332 |
| - |
333 |
| -} // End: function free_matrix() |
0 commit comments