-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEuler1D_LVec.jl
308 lines (226 loc) · 7.95 KB
/
Euler1D_LVec.jl
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# ============================================================================
# Euler1D_opt.jl
#
# By J.C. Toledo-Roy
# 18 / may / 2023
#
# Programa minimalista que resuelve el tubo de choque de Sod para las
# ecuaciones de Euler en 1D usando el método de Lax-Friedichs
#
# Versión optimizada usando la librería de terceros LoopVectorization.jl
#
# ==============================================================================
# using LoopVectorization
# ==============================================================================
# CONSTANTES Y VARIABLES GLOBALES
# ==============================================================================
# ----------------------------------------------------------------------------
# CONSTANTES Y VARIABLES GLOBALES ESPECIFICADAS POR EL USUARIO
# Parámetros de la simulación
const NEQ = 3 # Número de ecuaciones
const NX = 5000 # Tamaño de la malla
const XL = 0.0 # Coordenada física del extremo izquierdo
const XR = 1.0 # Coordenada física del extremo derecho
const TFIN = 0.20 # Tiempo final de integración
const CFL = 0.9 # Parametro de Courant
const DTOUT = TFIN/10 # Intervalo para escribir a disco
const GAMMA = 1.4 # Razón de capacidades caloríficas
# Directorio donde escribir las salidas (usar "./" para dir actual)
# Debe terminar en una diagonal '/'
const OUT_DIR = "./temp/"
const do_output = false
# ============================================================================
# NO ES NECESARIO MODIFICAR NADA DEBAJO DE ESTA LÍNEA
# ============================================================================
# Constantes calculadas de las anteriores
DX::Float64 = (XR-XL)/NX # Espaciamiento de la malla
# ----------------------------------------------------------------------------
# VARIABLES GLOBALES
U = zeros(Float64, (NX+2, NEQ)) # Variables conservadas actuales
UP = zeros(Float64, (NX+2, NEQ)) # Variables conservadas "avanzadas"
F = zeros(Float64, (NX+2, NEQ)) # Flujos físicos
UT = zeros(Float64, (NX+2, NEQ)) # Us temporales (sólo usadas en Macormack)
PRIM = zeros(Float64, (NX+2, NEQ)) # Variables primitivas
# Variables globales de la simulación
dt::Float64 = 0 # Paso de tiempo
t::Float64 = 0 # Tiempo actual
it::Int64 = 0 # Iteración actual
nout::Int64 = 0 # Número de la siguiente salida
tout::Float64 = 0 # Tiempo para el siguiente output
start_time::Float64 = 0 # Tiempo de inicio
# ==============================================================================
# CONDICIONES INICIALES
# ==============================================================================
# Devuelve la coordenada X de la celda i
function xcoord(i)
XL + i*DX
end
# ------------------------------------------------------------------------------
# Condición inicial
function initflow(U)
x0 = 0.5
rhoL = 1.0
uL = 0.0
pL = 1.0
rhoR = 0.125
uR = 0.0
pR = 0.1
U1L = rhoL
U2L = rhoL*uL
U3L = 0.5*rhoL*uL*uL + pL/(GAMMA-1)
U1R = rhoR
U2R = rhoR*uR
U3R = 0.5*rhoR*uR*uR + pR/(GAMMA-1)
for i in 1:NX+2
x = xcoord(i)
if (x <= x0)
U[i,1] = U1L
U[i,2] = U2L
U[i,3] = U3L
else
U[i,1] = U1R
U[i,2] = U2R
U[i,3] = U3R
end
end
end
# ==============================================================================
# Inicializaciones de variables globales del código
function initmain()
global t = 0.0
global it = 0
global tout = 0.0
global nout = 0
end
# ==============================================================================
# Aplicar condiciones de frontera a celdas fantasma
# El arreglo pasado es al que aplicaremos las BCs
function boundary(U)
# BC a la izquierda
for e in 1:NEQ
U[1,e] = U[2,e]
end
# BC a la derecha
for e in 1:NEQ
U[NX+2,e] = U[NX+1,e]
end
end
# ==============================================================================
# Calcula las primitivas a partir de las U pasadas
# Esto incluye las celdas fantasma
function flow2prim(U, PRIM)
@turbo for i in 1:NX+2
PRIM[i,1] = U[i,1]
PRIM[i,2] = U[i,2]/U[i,1]
PRIM[i,3] = (GAMMA-1)*(U[i,3] - U[i,2]*U[i,2]/(2*U[i,1]))
end
end
# ==============================================================================
# Calcular los flujos físicos F -- Ecuaciones de Euler 1D
# No olvidar calcular F en las celdas fantasma!
function fluxes(PRIM, F)
@turbo for i in 1:NX+2
F[i,1] = PRIM[i,1] * PRIM[i,2]
F[i,2] = PRIM[i,1] * PRIM[i,2]*PRIM[i,2] + PRIM[i,3]
F[i,3] = PRIM[i,2]*(0.5*PRIM[i,1]*PRIM[i,2]*PRIM[i,2] + GAMMA/(GAMMA-1)*PRIM[i,3])
end
end
# ==============================================================================
# Calcula el paso de tiempo resultante de la condición CFL
function timestep(PRIM, dt)
# Determinamos la velocidad máxima en la malla
max_speed = 0.0
for i in 2:NX+1
cs = sqrt(GAMMA*PRIM[i,3]/PRIM[i,1])
u_plus_cs = abs(PRIM[i,2]) + cs
if (u_plus_cs > max_speed)
max_speed = u_plus_cs
end
end
# Condición de estabilidad CFL
_dt = CFL * DX / max_speed
return _dt
end
# ==============================================================================
# SOLVERS NUMÉRICOS
# Método de Lax-Friedrichs
function Lax(U, F, UP)
@turbo for i in 2:NX+1
for e in 1:NEQ
UP[i,e] = (U[i+1,e] + U[i-1,e])/2 - dt/(2*DX) * (F[i+1,e] - F[i-1,e])
end
end
end
# ==============================================================================
# STEPPING
# Volcar las UPs sobre las Us "finales" del paso de tiempo -- sin viscosidad
function step(U, UP)
@turbo for i in 1:NX+1
for e in 1:NEQ
U[i,e] = UP[i,e]
end
end
# Avanzar el estado de la simulación
global t = t + dt
global it = it + 1
end
# ==============================================================================
# Escribe a disco el estado de la simulación
function output(PRIM)
if do_output
# Generar el nombre del archivo de salida
fname = "output_" * string(nout) * ".txt"
# Generar la ruta del archivo de salida (inc directorio)
fpath = OUT_DIR * fname
# Abrir el archivo para escritura
open(fpath, "w") do file
# Escribir los valores de PRIM al archivo (sólo celdas físicas)
for i in 2:NX+1
x = XL + i*DX
line = string(x) * " " * string(PRIM[i,1]) * " " * string(PRIM[i,2]) * " " * string(PRIM[i,3]) * "\n"
write(file, line)
end
println("Se escribió salida ", nout)
end
end
# Avanzar variables de output
global nout = nout + 1
global tout = DTOUT * nout
end
# ==============================================================================
# Programa principal
# ==============================================================================
function main()
start_time = time()
# Condición inicial e inicializaciones
initmain()
# Condición inicial e inicializaciones
initflow(U)
# Llenar celdas fantasma
boundary(U)
# Calcular las primitivas
flow2prim(U, PRIM)
# Escribir condición inicial a disco
output(PRIM)
# Bucle principal
while t < TFIN
# Calcular el paso de tiempo
global dt = timestep(PRIM, dt)
# Actualizar flujos físicos
fluxes(PRIM, F)
# Aplicar el método numérico para calcular las UP
Lax(U, F, UP)
# Aplicar condiciones de frontera a las UP recién calculadas
boundary(UP)
# Avanzar las U, con viscosidad para Macormack
step(U, UP)
# Actualizar las primitivas PRIM usando las nuevas U
flow2prim(U, PRIM)
# Escribir a disco
if (t >= tout)
output(PRIM)
end
end
println(time() - start_time)
end
# ==============================================================================