-
Notifications
You must be signed in to change notification settings - Fork 0
/
wave_1d_sequential.c
145 lines (111 loc) · 2.97 KB
/
wave_1d_sequential.c
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <sys/time.h>
// Option to change numerical precision.
typedef int64_t int_t;
typedef double real_t;
// Simulation parameters: size, step count, and how often to save the state.
const int_t
N = 65536,
max_iteration = 100000,
snapshot_freq = 500;
// Wave equation parameters, time step is derived from the space step.
const real_t
c = 1.0,
dx = 1.0;
real_t
dt;
// Buffers for three time steps, indexed with 2 ghost points for the boundary.
real_t
*buffers[3] = { NULL, NULL, NULL };
#define U_prv(i) buffers[0][(i)+1]
#define U(i) buffers[1][(i)+1]
#define U_nxt(i) buffers[2][(i)+1]
// Convert 'struct timeval' into seconds in double prec. floating point
#define WALLTIME(t) ((double)(t).tv_sec + 1e-6 * (double)(t).tv_usec)
// Save the present time step in a numbered file under 'data/'.
void domain_save ( int_t step )
{
char filename[256];
sprintf ( filename, "data/%.5ld.dat", step );
FILE *out = fopen ( filename, "wb" );
fwrite ( &U(0), sizeof(real_t), N, out );
fclose ( out );
}
// Set up our three buffers, fill two with an initial cosine wave,
// and set the time step.
void domain_initialize ( void )
{
buffers[0] = malloc ( (N+2)*sizeof(real_t) );
buffers[1] = malloc ( (N+2)*sizeof(real_t) );
buffers[2] = malloc ( (N+2)*sizeof(real_t) );
for ( int_t i=0; i<N; i++ )
{
U_prv(i) = U(i) = cos ( M_PI*i / (real_t)N );
}
// Set the time step for 1D case.
dt = dx / c;
}
// Return the memory to the OS.
void domain_finalize ( void )
{
free ( buffers[0] );
free ( buffers[1] );
free ( buffers[2] );
}
// Rotate the time step buffers.
void move_buffer_window ( void )
{
real_t *temp = buffers[0];
buffers[0] = buffers[1];
buffers[1] = buffers[2];
buffers[2] = temp;
}
// Derive step t+1 from steps t and t-1.
void time_step ( void )
{
for ( int_t i=0; i<N; i++ )
{
U_nxt(i) = -U_prv(i) + 2.0*U(i)
+ (dt*dt*c*c)/(dx*dx) * (U(i-1)+U(i+1)-2.0*U(i));
}
}
// Neumann (reflective) boundary condition.
void boundary_condition ( void )
{
U(-1) = U(1);
U(N) = U(N-2);
}
// Main time integration.
void simulate( void )
{
// Go through each time step.
for ( int_t iteration=0; iteration<=max_iteration; iteration++ )
{
if ( (iteration % snapshot_freq)==0 )
{
domain_save ( iteration / snapshot_freq );
}
// Derive step t+1 from steps t and t-1.
boundary_condition();
time_step();
move_buffer_window();
}
}
int main ( void )
{
struct timeval t_start, t_end;
domain_initialize();
gettimeofday ( &t_start, NULL );
simulate();
gettimeofday ( &t_end, NULL );
printf ( "Total elapsed time: %lf seconds\n",
WALLTIME(t_end) - WALLTIME(t_start)
);
domain_finalize();
exit ( EXIT_SUCCESS );
}