fargopy 0.3.11__py3-none-any.whl → 0.3.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fargopy/__init__.py CHANGED
@@ -351,6 +351,7 @@ from fargopy.sys import *
351
351
  from fargopy.fields import *
352
352
  from fargopy.simulation import *
353
353
  from fargopy.plot import *
354
+ #from fargopy.Fsimulation
354
355
 
355
356
  # Showing version
356
357
  print(f"Running FARGOpy version {version}")
fargopy/fsimulation.py ADDED
@@ -0,0 +1,603 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ import fargopy as fp
4
+
5
+
6
+ import matplotlib.pyplot as plt
7
+ import plotly.figure_factory as ff
8
+ from plotly.subplots import make_subplots
9
+ import plotly.graph_objects as go
10
+ from matplotlib.animation import FFMpegWriter
11
+
12
+ from ipywidgets import interact, FloatSlider,IntSlider
13
+ from celluloid import Camera
14
+ from IPython.display import HTML
15
+ from IPython.display import Video
16
+
17
+ from scipy.interpolate import griddata
18
+ from scipy.integrate import solve_ivp
19
+ from tqdm import tqdm
20
+
21
+
22
+
23
+
24
+ class DataHandler:
25
+ def __init__(self, sim):
26
+ self.sim = sim
27
+ self.df = None
28
+ self.plane = None
29
+
30
+ def load_data(self, plane, angle, num_snapshots):
31
+ self.plane = plane
32
+ snapshots = np.arange(1, num_snapshots + 1)
33
+ time_values = snapshots / num_snapshots
34
+
35
+ df_snapshots = pd.DataFrame(columns=["snapshot", "time", "vel1", "vel2", "gasdens", "coord1", "coord2"])
36
+
37
+ for i, snap in enumerate(snapshots):
38
+ gasv = self.sim.load_field('gasv', snapshot=snap, type='vector')
39
+ gasvx, gasvy, gasvz = gasv.to_cartesian()
40
+ gasd = self.sim.load_field('gasdens', snapshot=snap, type='scalar')
41
+
42
+ if plane == 'XZ':
43
+ vel1_slice, mesh = gasvx.meshslice(slice=angle)
44
+ vel2_slice, _ = gasvz.meshslice(slice=angle)
45
+ coord1, coord2 = mesh.x, mesh.z
46
+ elif plane == 'XY':
47
+ vel1_slice, mesh = gasvx.meshslice(slice=angle)
48
+ vel2_slice, _ = gasvy.meshslice(slice=angle)
49
+ coord1, coord2 = mesh.x, mesh.y
50
+ elif plane == 'YZ':
51
+ vel1_slice, mesh = gasvy.meshslice(slice='r=1.0')
52
+ vel2_slice, _ = gasvz.meshslice(slice='r=1.0')
53
+ coord1, coord2 = mesh.y, mesh.z
54
+
55
+ gasd_slice, _ = gasd.meshslice(slice=angle)
56
+ df_snapshots.loc[i] = [snap, time_values[i], vel1_slice, vel2_slice, gasd_slice, coord1, coord2]
57
+
58
+ self.df = df_snapshots
59
+ return df_snapshots
60
+
61
+ def interpolate_field(self, time, var1, var2, field_name):
62
+ df_sorted = self.df.sort_values("time")
63
+ idx = df_sorted["time"].searchsorted(time) - 1
64
+ if idx == -1:
65
+ idx = 0
66
+ idx_after = min(idx + 1, len(df_sorted) - 1)
67
+
68
+ t0, t1 = df_sorted.iloc[idx]["time"], df_sorted.iloc[idx_after]["time"]
69
+ factor = (time - t0) / (t1 - t0) if t1 > t0 else 0
70
+ if factor < 0:
71
+ factor = 0
72
+
73
+ def interp(idx):
74
+ coord1, coord2 = df_sorted.iloc[idx]["coord1"], df_sorted.iloc[idx]["coord2"]
75
+ points = np.column_stack((coord1.ravel(), coord2.ravel()))
76
+ data = df_sorted.iloc[idx][field_name].ravel()
77
+ return griddata(points, data, (var1, var2), method='linear', fill_value=0.0)
78
+
79
+ result = (1 - factor) * interp(idx) + factor * interp(idx_after)
80
+ return result
81
+
82
+ def interpolate_velocity(self, time, var1, var2):
83
+ v1 = self.interpolate_field(time, var1, var2, "vel1")
84
+ v2 = self.interpolate_field(time, var1, var2, "vel2")
85
+ return v1, v2
86
+
87
+ def interpolate_density(self, time, var1, var2):
88
+ return self.interpolate_field(time, var1, var2, "gasdens")
89
+
90
+
91
+ class Simulation:
92
+ def __init__(self, plane, angle, num_snapshots, dir_path):
93
+ self.sim = fp.Simulation(output_dir=dir_path)
94
+ self.data_handler = DataHandler(self.sim)
95
+ self.data_handler.load_data(plane, angle, num_snapshots)
96
+
97
+ def velocity_field(self, t, y):
98
+ var1, var2 = y
99
+ v1, v2 = self.data_handler.interpolate_velocity(t, np.array([var1]), np.array([var2]))
100
+ return np.array([v1[0], v2[0]])
101
+
102
+ def integrate_particles(self, particle_pos, time, dt=0.01):
103
+ """ Integra todas las partículas con un paso explícito de Euler."""
104
+ if len(particle_pos) == 0:
105
+ return np.array([])
106
+
107
+ v1, v2 = self.data_handler.interpolate_velocity(time, particle_pos[:, 0], particle_pos[:, 1])
108
+
109
+ # Paso de Euler: x_{n+1} = x_n + v * dt
110
+ particle_pos[:, 0] += v1 * dt
111
+ particle_pos[:, 1] += v2 * dt
112
+
113
+ return particle_pos
114
+
115
+ def generate_uniform_particles(self, var1_min, var1_max, var2_min, var2_max, num_particles):
116
+ grid_size = int(np.sqrt(num_particles))
117
+ var1_candidates = np.linspace(var1_min + 0.01, var1_max - 0.01, grid_size)
118
+ var2_candidates = np.linspace(var2_min + 0.001, var2_max - 0.001, grid_size)
119
+ VAR1_grid, VAR2_grid = np.meshgrid(var1_candidates, var2_candidates, indexing='ij')
120
+
121
+ density_values = self.data_handler.interpolate_density(0, VAR1_grid, VAR2_grid)
122
+ valid_mask = density_values > 0
123
+
124
+ valid_var1 = VAR1_grid[valid_mask]
125
+ valid_var2 = VAR2_grid[valid_mask]
126
+
127
+ if len(valid_var1) == 0:
128
+ return []
129
+
130
+ num_valid_points = min(num_particles, len(valid_var1))
131
+ new_particles = np.column_stack((valid_var1[:num_valid_points], valid_var2[:num_valid_points]))
132
+
133
+ return new_particles
134
+
135
+ def run_simulation(self, res, var1_min, var1_max, var2_min, var2_max, ts, npi, max_lifetime, generation_interval):
136
+ var1_reg, var2_reg = np.linspace(var1_min, var1_max, res), np.linspace(var2_min, var2_max, res)
137
+ VAR1_reg, VAR2_reg = np.meshgrid(var1_reg, var2_reg, indexing='ij')
138
+
139
+ t_span = (0, 1)
140
+ t_eval = np.linspace(t_span[0], t_span[1], ts)
141
+
142
+ particle_pos = np.empty((0, 2))
143
+ lifetimes = np.empty(0)
144
+ new_particles = self.generate_uniform_particles(var1_min, var1_max, var2_min, var2_max, npi)
145
+
146
+ # Determinar el label del eje y en función del plano
147
+ plane = self.data_handler.plane
148
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
149
+
150
+ fig, ax = plt.subplots(figsize=(8, 8))
151
+ camera = Camera(fig)
152
+
153
+ with tqdm(total=len(t_eval), desc="Generando animación", unit="frame") as pbar:
154
+ for frame in range(len(t_eval)):
155
+ time = t_eval[frame]
156
+ if frame % generation_interval == 0:
157
+ particle_pos = np.vstack([particle_pos, new_particles])
158
+ lifetimes = np.concatenate([lifetimes, np.full(len(new_particles), max_lifetime)])
159
+
160
+ updated_pos = self.integrate_particles(particle_pos, time, dt=0.01)
161
+ updated_pos = np.array([pos for pos in updated_pos if pos is not None])
162
+ updated_lifetimes = lifetimes - 1
163
+
164
+ valid_indices = updated_lifetimes > 0
165
+ particle_pos = updated_pos[valid_indices]
166
+ lifetimes = updated_lifetimes[valid_indices]
167
+
168
+ lifetimes_normalized = lifetimes / max_lifetime
169
+
170
+ # Agregar interpolación de densidad como fondo
171
+ gasd_interpolated = self.data_handler.interpolate_density(time, VAR1_reg, VAR2_reg)
172
+ c = ax.pcolormesh(VAR1_reg, VAR2_reg, np.log10(gasd_interpolated * self.sim.URHO * 1e3),
173
+ cmap="viridis", shading='auto')
174
+
175
+ # Graficar partículas
176
+ if len(particle_pos) > 0:
177
+ ax.scatter(particle_pos[:, 0], particle_pos[:, 1], c='lightgray', alpha=lifetimes_normalized, s=1.0)
178
+
179
+ ax.set_xlim(var1_min, var1_max)
180
+ ax.set_ylim(var2_min, var2_max)
181
+ ax.set_xlabel(r"$r \ [AU]$",size=12)
182
+ ax.set_ylabel(y_label,size=12)
183
+ camera.snap()
184
+
185
+ pbar.update(1)
186
+
187
+ # Agregar barra de color
188
+ fig.colorbar(c, ax=ax, label=r'$\log_{10}(\rho)$ [kg/m$^3$]')
189
+ plt.close(fig)
190
+ animation = camera.animate()
191
+ video_filename = 'figures/streaklines.mp4'
192
+ animation.save(video_filename, writer=FFMpegWriter(fps=10, codec='libx264', bitrate=5000))
193
+
194
+ # Mostrar el video en el entorno interactivo
195
+ return Video(video_filename, embed=True)
196
+
197
+
198
+ class Visualize:
199
+ def __init__(self, data_handler):
200
+ """
201
+ Inicializa la clase Visualize con una instancia de DataHandler.
202
+ """
203
+ self.data_handler = data_handler
204
+
205
+ def density(self, var1_min, var1_max, var2_min, var2_max, res, time):
206
+ """
207
+ Grafica un mapa de contornos de densidad interpolada en un tiempo dado.
208
+ """
209
+ # Crear una cuadrícula regular para las coordenadas
210
+ var1 = np.linspace(var1_min, var1_max, res)
211
+ var2 = np.linspace(var2_min, var2_max, res)
212
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
213
+
214
+ # Interpolar la densidad en el tiempo dado
215
+ density = self.data_handler.interpolate_density(time, VAR1, VAR2).T
216
+
217
+ # Determinar el label del eje y en función del plano
218
+ plane = self.data_handler.plane
219
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
220
+
221
+ # Crear el gráfico de contorno
222
+ fig = go.Figure(
223
+ data=go.Contour(
224
+ z=np.log10(density * self.data_handler.sim.URHO * 1e3),
225
+ x=var1,
226
+ y=var2,
227
+ colorscale="Spectral_r",
228
+ contours=dict(coloring="heatmap"),
229
+ colorbar=dict(title="log10(ρ) [kg/m³]")
230
+ )
231
+ )
232
+
233
+ # Configurar el diseño del gráfico
234
+ fig.update_layout(
235
+ title=f"Mapa de Contornos de Densidad (t = {time:.2f})",
236
+ xaxis_title="r [AU]",
237
+ yaxis_title=y_label,
238
+ width=600,
239
+ height=600
240
+ )
241
+
242
+ # Mostrar el gráfico
243
+ fig.show()
244
+
245
+
246
+
247
+
248
+ def animate_density(self, var1_min, var1_max, var2_min, var2_max, res, time_array):
249
+
250
+ # Crear una cuadrícula regular para las coordenadas
251
+ var1 = np.linspace(var1_min, var1_max, res)
252
+ var2 = np.linspace(var2_min, var2_max, res)
253
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
254
+
255
+ # Precalcular el campo de densidad para todos los tiempos
256
+ precalculated_density = [
257
+ self.data_handler.interpolate_density(time, VAR1, VAR2).T
258
+ for time in time_array
259
+ ]
260
+ # Determinar el label del eje y en función del plano
261
+ plane = self.data_handler.plane
262
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
263
+
264
+ # Crear la figura inicial
265
+ initial_density = precalculated_density[0]
266
+ fig = go.Figure(
267
+ data=go.Contour(
268
+ z=np.log10(initial_density * self.data_handler.sim.URHO * 1e3),
269
+ x=var1,
270
+ y=var2,
271
+ colorscale="Spectral_r",
272
+ contours=dict(coloring="heatmap"),
273
+ colorbar=dict(title="log10(ρ) [kg/m³]")
274
+ )
275
+ )
276
+
277
+ # Crear los frames para la animación
278
+ frames = []
279
+ for i, time in enumerate(time_array):
280
+ density = precalculated_density[i]
281
+ frames.append(go.Frame(
282
+ data=go.Contour(
283
+ z=np.log10(density * self.data_handler.sim.URHO * 1e3),
284
+ x=var1,
285
+ y=var2,
286
+ colorscale="Spectral_r", # Este colormap será actualizado dinámicamente
287
+ contours=dict(coloring="heatmap")
288
+ ),
289
+ name=f"{time:.2f}"
290
+ ))
291
+
292
+ fig.frames = frames
293
+
294
+ # Configurar el slider
295
+ sliders = [
296
+ dict(
297
+ steps=[
298
+ dict(
299
+ method="animate",
300
+ args=[[f"{time:.2f}"], dict(mode="immediate", frame=dict(duration=100, redraw=True), transition=dict(duration=0))],
301
+ label=f"{time:.2f}"
302
+ )
303
+ for time in time_array
304
+ ],
305
+ transition=dict(duration=0),
306
+ currentvalue=dict(font=dict(size=16), prefix="Tiempo: ", visible=True),
307
+ len=0.9
308
+ )
309
+ ]
310
+
311
+ # Configurar los botones de reproducción y pausa
312
+ updatemenus = [
313
+ dict(
314
+ type="buttons",
315
+ showactive=False,
316
+ buttons=[
317
+ dict(label="Play",
318
+ method="animate",
319
+ args=[None, dict(frame=dict(duration=100, redraw=True), fromcurrent=True)]),
320
+ dict(label="Pause",
321
+ method="animate",
322
+ args=[[None], dict(frame=dict(duration=0, redraw=False), mode="immediate")])
323
+ ]
324
+ )
325
+ ]
326
+
327
+ # Actualizar el diseño de la figura
328
+ fig.update_layout(
329
+ title="Evolución del Campo de Densidad",
330
+ xaxis_title='r [AU]',
331
+ yaxis_title=y_label,
332
+ width=600,
333
+ height=600,
334
+ sliders=sliders,
335
+ updatemenus=updatemenus
336
+ )
337
+
338
+ # Mostrar la animación
339
+ fig.show()
340
+
341
+ def velocity(self, var1_min, var1_max, var2_min, var2_max, res, time):
342
+ """
343
+ Grafica un mapa de magnitud de velocidad interpolada en un tiempo dado.
344
+ Las zonas donde la interpolación da 0 no serán coloreadas.
345
+ """
346
+ # Crear una cuadrícula regular para las coordenadas
347
+ var1 = np.linspace(var1_min, var1_max, res)
348
+ var2 = np.linspace(var2_min, var2_max, res)
349
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
350
+
351
+ # Interpolar el campo de velocidad en el tiempo dado
352
+ velocity_x, velocity_y = self.data_handler.interpolate_velocity(time, VAR1, VAR2)
353
+
354
+ # Calcular la magnitud de la velocidad
355
+ velocity_magnitude = np.sqrt(velocity_x**2 + velocity_y**2).T * self.data_handler.sim.UV / (1e5) # Convertir a km/s
356
+
357
+ # Establecer las zonas donde velocity_x y velocity_y son 0 como None
358
+ velocity_magnitude[velocity_magnitude==0] = None
359
+
360
+ # Determinar el label del eje y en función del plano
361
+ plane = self.data_handler.plane
362
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
363
+
364
+ # Crear el gráfico de contorno
365
+ fig = go.Figure(
366
+ data=go.Contour(
367
+ z=velocity_magnitude,
368
+ x=var1,
369
+ y=var2,
370
+ colorscale="Viridis",
371
+ contours=dict(coloring="heatmap"),
372
+ colorbar=dict(title="|v| [km/s]"),
373
+ zmin=np.nanmin(velocity_magnitude),
374
+ zmax=np.nanmax(velocity_magnitude),
375
+ showscale=True
376
+ )
377
+ )
378
+
379
+ # Configurar el diseño del gráfico
380
+ fig.update_layout(
381
+ title=f"Mapa de Velocidad (t = {time:.2f})",
382
+ xaxis_title="r [AU]",
383
+ yaxis_title=y_label,
384
+ width=600,
385
+ height=600,
386
+ plot_bgcolor="white" # Fondo blanco para que las zonas no coloreadas sean visibles
387
+ )
388
+
389
+ # Mostrar el gráfico
390
+ fig.show()
391
+
392
+ def animate_velocity(self, var1_min, var1_max, var2_min, var2_max, res, time_array):
393
+ """
394
+ Crea una animación del mapa de magnitud de velocidad interpolada en función del tiempo.
395
+ Las zonas donde la magnitud de la velocidad es 0 no serán coloreadas.
396
+ """
397
+ # Crear una cuadrícula regular para las coordenadas
398
+ var1 = np.linspace(var1_min, var1_max, res)
399
+ var2 = np.linspace(var2_min, var2_max, res)
400
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
401
+
402
+ # Determinar el label del eje y en función del plano
403
+ plane = self.data_handler.plane
404
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
405
+
406
+ # Precalcular la magnitud del campo de velocidad para todos los tiempos
407
+ precalculated_velocity_magnitude = []
408
+ for time in time_array:
409
+ velocity_x, velocity_y = self.data_handler.interpolate_velocity(time, VAR1, VAR2)
410
+ velocity_magnitude = np.sqrt(velocity_x**2 + velocity_y**2).T * self.data_handler.sim.UV / (1e5) # Convertir a km/s
411
+ velocity_magnitude[velocity_magnitude == 0] = None # Reemplazar las zonas con magnitud 0 por None
412
+ precalculated_velocity_magnitude.append(velocity_magnitude)
413
+
414
+ # Crear la figura inicial
415
+ initial_velocity_magnitude = precalculated_velocity_magnitude[0]
416
+ fig = go.Figure(
417
+ data=go.Contour(
418
+ z=initial_velocity_magnitude,
419
+ x=var1,
420
+ y=var2,
421
+ colorscale="Viridis",
422
+ contours=dict(coloring="heatmap"),
423
+ colorbar=dict(title="|v| [km/s]")
424
+ )
425
+ )
426
+
427
+ # Crear los frames para la animación
428
+ frames = []
429
+ for i, time in enumerate(time_array):
430
+ velocity_magnitude = precalculated_velocity_magnitude[i]
431
+ frames.append(go.Frame(
432
+ data=go.Contour(
433
+ z=velocity_magnitude,
434
+ x=var1,
435
+ y=var2,
436
+ colorscale="Viridis",
437
+ contours=dict(coloring="heatmap")
438
+ ),
439
+ name=f"{time:.2f}"
440
+ ))
441
+
442
+ fig.frames = frames
443
+
444
+ # Configurar el slider
445
+ sliders = [
446
+ dict(
447
+ steps=[
448
+ dict(
449
+ method="animate",
450
+ args=[[f"{time:.2f}"], dict(mode="immediate", frame=dict(duration=150, redraw=True), transition=dict(duration=0))],
451
+ label=f"{time:.2f}"
452
+ )
453
+ for time in time_array
454
+ ],
455
+ transition=dict(duration=0),
456
+ currentvalue=dict(font=dict(size=16), prefix="Tiempo: ", visible=True),
457
+ len=0.9
458
+ )
459
+ ]
460
+
461
+ # Configurar los botones de reproducción y pausa
462
+ updatemenus = [
463
+ dict(
464
+ type="buttons",
465
+ showactive=False,
466
+ buttons=[
467
+ dict(label="Play",
468
+ method="animate",
469
+ args=[None, dict(frame=dict(duration=100, redraw=True), fromcurrent=True)]),
470
+ dict(label="Pause",
471
+ method="animate",
472
+ args=[[None], dict(frame=dict(duration=0, redraw=False), mode="immediate")])
473
+ ]
474
+ )
475
+ ]
476
+
477
+ # Actualizar el diseño de la figura
478
+ fig.update_layout(
479
+ title="Evolución del Campo de Velocidad",
480
+ xaxis_title='r [AU]',
481
+ yaxis_title=y_label,
482
+ width=600,
483
+ height=600,
484
+ sliders=sliders,
485
+ updatemenus=updatemenus
486
+ )
487
+
488
+ # Mostrar la animación
489
+ fig.show()
490
+
491
+ def vel_streamlines(self, var1_min, var1_max, var2_min, var2_max, res, time):
492
+ """
493
+ Grafica las streamlines del campo de velocidad con la densidad de fondo para un tiempo dado.
494
+ """
495
+ # Crear una cuadrícula regular para las coordenadas
496
+ var1 = np.linspace(var1_min, var1_max, res)
497
+ var2 = np.linspace(var2_min, var2_max, res)
498
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
499
+
500
+ # Interpolar el campo de densidad y velocidad en el tiempo dado
501
+ density = self.data_handler.interpolate_density(time, VAR1, VAR2)
502
+ velocity_x, velocity_y = self.data_handler.interpolate_velocity(time, VAR1, VAR2)
503
+
504
+ # Calcular la magnitud de la velocidad
505
+ v_mag = np.sqrt(velocity_x**2 + velocity_y**2).T * self.data_handler.sim.UV / (1e5) # Convertir a km/s
506
+
507
+ # Determinar el label del eje y en función del plano
508
+ plane = self.data_handler.plane
509
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
510
+
511
+ # Crear el gráfico
512
+ plt.figure(figsize=(6, 6))
513
+ plt.pcolormesh(var1, var2, np.log10(density * self.data_handler.sim.URHO * 1e3).T, cmap="Spectral_r", shading='auto')
514
+ plt.streamplot(var1, var2, velocity_x.T, velocity_y.T, color=v_mag, linewidth=0.7, density=3.0, cmap='viridis')
515
+ plt.colorbar(label="|v| [km/s]")
516
+ plt.title(f"Streamlines (t = {time:.2f})")
517
+ plt.xlabel("r [AU]")
518
+ plt.ylabel(y_label)
519
+ plt.show()
520
+
521
+ def vel_streamlines_slide(self, var1_min, var1_max, var2_min, var2_max, res, time_array):
522
+
523
+ # Crear una cuadrícula regular para las coordenadas
524
+ var1 = np.linspace(var1_min, var1_max, res)
525
+ var2 = np.linspace(var2_min, var2_max, res)
526
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
527
+ # Determinar el label del eje y en función del plano
528
+ plane = self.data_handler.plane
529
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
530
+
531
+ # Precalcular densidad y velocidades para todos los tiempos
532
+ precalculated_data = [
533
+ {
534
+ "density": self.data_handler.interpolate_density(time, VAR1, VAR2),
535
+ "velocity": self.data_handler.interpolate_velocity(time, VAR1, VAR2)
536
+ }
537
+ for time in time_array
538
+ ]
539
+
540
+ def update_plot(time_index):
541
+ """
542
+ Actualiza el gráfico para un índice de tiempo dado.
543
+ """
544
+ data = precalculated_data[time_index]
545
+ density = data["density"]
546
+ velocity_x = data["velocity"][0]
547
+ velocity_y = data["velocity"][1]
548
+ v_mag = np.sqrt(velocity_x**2 + velocity_y**2).T*self.data_handler.sim.UV/(1e5)
549
+ # Crear el gráfico
550
+ plt.figure(figsize=(6, 6))
551
+ plt.pcolormesh(var1, var2, np.log10(density * self.data_handler.sim.URHO * 1e3).T, cmap="Spectral_r", shading='auto')
552
+ plt.streamplot(var1, var2, velocity_x.T, velocity_y.T, color=v_mag, linewidth=0.7, density=3.0,cmap='viridis')
553
+ plt.colorbar(label="|v| [km/s]")
554
+ plt.title(f"Streamlines (t = {time_array[time_index]:.2f})")
555
+ plt.xlabel("r [AU]")
556
+ plt.ylabel(y_label)
557
+ plt.show()
558
+
559
+ # Crear un slider interactivo para el tiempo (con índices enteros)
560
+ interact(update_plot, time_index=IntSlider(value=0, min=0, max=len(time_array) - 1, step=1))
561
+
562
+
563
+ def vel_streamlines_vid(self, var1_min, var1_max, var2_min, var2_max, res, time_array,output_file="streamlines_animation.mp4"):
564
+
565
+ # Crear una cuadrícula regular para las coordenadas
566
+ var1 = np.linspace(var1_min, var1_max, res)
567
+ var2 = np.linspace(var2_min, var2_max, res)
568
+ VAR1, VAR2 = np.meshgrid(var1, var2, indexing='ij')
569
+ # Determinar el label del eje y en función del plano
570
+ plane = self.data_handler.plane
571
+ y_label = "Z [AU]" if plane == "XZ" else r"$\phi$ [rad]"
572
+
573
+ # Configurar la figura y la cámara para la animación
574
+ fig, ax = plt.subplots(figsize=(6, 6))
575
+ camera = Camera(fig)
576
+
577
+ # Generar los frames de la animación
578
+ for time in time_array:
579
+ # Interpolar el campo de densidad y velocidad
580
+ density = self.data_handler.interpolate_density(time, VAR1, VAR2)
581
+ velocity_x, velocity_y = self.data_handler.interpolate_velocity(time, VAR1, VAR2)
582
+ v_mag = np.sqrt(velocity_x**2 + velocity_y**2).T*self.data_handler.sim.UV/(1e5)
583
+
584
+ # Crear el gráfico para el frame actual
585
+ c = ax.pcolormesh(var1, var2, np.log10(density * self.data_handler.sim.URHO * 1e3).T, cmap="Spectral_r", shading='auto')
586
+ strm=ax.streamplot(var1, var2, velocity_x.T, velocity_y.T, color=v_mag, linewidth=0.7, density=3.0,cmap='viridis')
587
+ ax.set_xlabel("r [AU]")
588
+ ax.set_ylabel(y_label)
589
+ camera.snap()
590
+
591
+
592
+ # Crear la animación
593
+ fig.colorbar(strm.lines, ax=ax, label="|v| [km/s]")
594
+ plt.close(fig)
595
+ animation = camera.animate()
596
+
597
+
598
+ # Guardar la animación en un archivo
599
+ animation.save(output_file, writer="ffmpeg", fps=10)
600
+
601
+ plt.close(fig)
602
+ return Video(output_file, embed=True)
603
+
fargopy/simulation.py CHANGED
@@ -60,7 +60,9 @@ PRECOMPUTED_SIMULATIONS = dict(
60
60
  size=140
61
61
  ),
62
62
  )
63
- signal.signal(signal.SIGCHLD, signal.SIG_IGN)
63
+
64
+ if not fargopy.IN_COLAB:
65
+ signal.signal(signal.SIGCHLD, signal.SIG_IGN)
64
66
 
65
67
  ###############################################################
66
68
  # Classes
@@ -531,7 +533,7 @@ class Simulation(fargopy.Fargobj):
531
533
 
532
534
  if 'progress' in mode:
533
535
  vprint(bar)
534
- numstatus = 10
536
+ numstatus = 5
535
537
  if 'numstatus' in kwargs.keys():
536
538
  numstatus = int(kwargs['numstatus'])
537
539
  self._status_progress(numstatus=numstatus)
@@ -594,9 +596,9 @@ class Simulation(fargopy.Fargobj):
594
596
  try:
595
597
  time.sleep(frequency)
596
598
  except KeyboardInterrupt:
597
- print("Interrupted by user")
599
+ print("Interrupted by user. In some environment (IPython, Colab) stopping the progress status will stop the simulation. In that case just resume.")
598
600
  return
599
-
601
+
600
602
  else:
601
603
  # Suitable for running in Jupyter and IPython
602
604
  if fargopy.Sys.sleep_timeout(frequency):
fargopy/version.py CHANGED
@@ -1 +1 @@
1
- version='0.3.11'
1
+ version='0.3.13'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: fargopy
3
- Version: 0.3.11
3
+ Version: 0.3.13
4
4
  Summary: FARGO3D Wrapping
5
5
  Home-page: https://pypi.org/project/fargopy
6
6
  Author: Jorge Zuluaga, Matias Montesinos
@@ -20,6 +20,21 @@ Requires-Dist: ipython
20
20
  Requires-Dist: celluloid
21
21
  Requires-Dist: psutil
22
22
  Requires-Dist: gdown
23
+ Requires-Dist: pandas
24
+ Requires-Dist: plotly
25
+ Requires-Dist: ipywidgets
26
+ Requires-Dist: nbformat
27
+ Dynamic: author
28
+ Dynamic: author-email
29
+ Dynamic: classifier
30
+ Dynamic: description
31
+ Dynamic: description-content-type
32
+ Dynamic: home-page
33
+ Dynamic: keywords
34
+ Dynamic: license
35
+ Dynamic: license-file
36
+ Dynamic: requires-dist
37
+ Dynamic: summary
23
38
 
24
39
  # FARGOpy
25
40
  ## Wrapping FRAGO3D
@@ -0,0 +1,16 @@
1
+ fargopy/__init__.py,sha256=Ua0ORnNZRgXeU1A-SlT5p2YBBs8x-O30Vwu2xh8b3mg,12490
2
+ fargopy/fields.py,sha256=--TrrAaFO9WmsrecRfdmEV1FRfp6JQRlIqyqGn11p2g,10128
3
+ fargopy/fsimulation.py,sha256=jfaLxgNePUx1seUv4uP5BHhxzU02wAmKbpE25wYnR1Y,23912
4
+ fargopy/plot.py,sha256=T2xhVQnBU9NVebxgMgegcuBc0YZSei12VC6OzD5JihI,1583
5
+ fargopy/simulation.py,sha256=MiVkFsm9irt90xFgAcS_2oz467L-Ox5z2eCtIichuZs,41976
6
+ fargopy/sys.py,sha256=O53WNHU3EL3GIrpxuK4mi2er929f6Ztdf5Fej62DDs8,5055
7
+ fargopy/util.py,sha256=Bbll0TwJjFp5hv2luoBu9ogNiepp4oErPFcuty7YqdY,672
8
+ fargopy/version.py,sha256=ceu-tteg-ZvlRki8tggpXZY2ryJDEoTdx2TxbH5v3I0,17
9
+ fargopy/tests/test___init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ fargopy-0.3.13.data/scripts/ifargopy,sha256=t5E07jKzOLtNnlNyElQZbzjCW6wnR0bc8uCaZpw9yS8,382
11
+ fargopy-0.3.13.dist-info/licenses/LICENSE,sha256=aIckKnNVrkXQMqEKlzGn_REfTwc82TF35BHMCRwPXCI,1097
12
+ fargopy-0.3.13.dist-info/METADATA,sha256=LWo07_58-BkX-zuZIhbojyNUE3txo8R2VEPSvD5G21Q,17689
13
+ fargopy-0.3.13.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
+ fargopy-0.3.13.dist-info/entry_points.txt,sha256=555NPKYbLCN0fgJbdW4b4azZ5sqjhqVqTUxujBBYEJY,49
15
+ fargopy-0.3.13.dist-info/top_level.txt,sha256=_r66v1_-9T7dB5sQa12AdxaAdsv9-OTwtR-vft4OPBU,8
16
+ fargopy-0.3.13.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,15 +0,0 @@
1
- fargopy/__init__.py,sha256=TgVTZSO5vMpUXX5SB4Gx56vak6lcG3o0JZkt43ZZB9g,12464
2
- fargopy/fields.py,sha256=--TrrAaFO9WmsrecRfdmEV1FRfp6JQRlIqyqGn11p2g,10128
3
- fargopy/plot.py,sha256=T2xhVQnBU9NVebxgMgegcuBc0YZSei12VC6OzD5JihI,1583
4
- fargopy/simulation.py,sha256=izXGxhLk8bDvLUT-u76gcNBmgT8lRwEjQe4yGRRdmuU,41812
5
- fargopy/sys.py,sha256=O53WNHU3EL3GIrpxuK4mi2er929f6Ztdf5Fej62DDs8,5055
6
- fargopy/util.py,sha256=Bbll0TwJjFp5hv2luoBu9ogNiepp4oErPFcuty7YqdY,672
7
- fargopy/version.py,sha256=cbXwx6BNwzOs_pGkTmZsPUt7d7bVrFJI0ea6h2uhGPM,17
8
- fargopy/tests/test___init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- fargopy-0.3.11.data/scripts/ifargopy,sha256=t5E07jKzOLtNnlNyElQZbzjCW6wnR0bc8uCaZpw9yS8,382
10
- fargopy-0.3.11.dist-info/LICENSE,sha256=aIckKnNVrkXQMqEKlzGn_REfTwc82TF35BHMCRwPXCI,1097
11
- fargopy-0.3.11.dist-info/METADATA,sha256=s0hA5E5JEWQ8WXKJgwQ9poEqfb_-h7Ok22ze1CM-AxI,17366
12
- fargopy-0.3.11.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
13
- fargopy-0.3.11.dist-info/entry_points.txt,sha256=555NPKYbLCN0fgJbdW4b4azZ5sqjhqVqTUxujBBYEJY,49
14
- fargopy-0.3.11.dist-info/top_level.txt,sha256=_r66v1_-9T7dB5sQa12AdxaAdsv9-OTwtR-vft4OPBU,8
15
- fargopy-0.3.11.dist-info/RECORD,,