Skip to content

Commit 7d14e65

Browse files
authored
Small adjustments
1 parent 5b9a248 commit 7d14e65

File tree

1 file changed

+4
-327
lines changed

1 file changed

+4
-327
lines changed

Project4/main.cpp

+4-327
Original file line numberDiff line numberDiff line change
@@ -1,333 +1,10 @@
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>
111
#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;
202

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;
384

39-
// Main program begins here
40-
41-
int main(int argc, char* argv[])
5+
int main()
426
{
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;
1299
}
13010

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

Comments
 (0)