Skip to content

Commit 56b124a

Browse files
code cleanup. interface/parameter changes.
1 parent 3d7fbfb commit 56b124a

File tree

13 files changed

+1195
-605
lines changed

13 files changed

+1195
-605
lines changed

README.md

Lines changed: 87 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ obs = Observer(lumi_dist=1e26, z=0.1, theta_obs=0) #in cgs unit
212212
rad = Radiation(eps_e=1e-1, eps_B=1e-3, p=2.3)
213213

214214
# 5. Combine all components into a complete afterglow model
215-
model = Model(jet=jet, medium=medium, observer=obs, forward_rad=rad)
215+
model = Model(jet=jet, medium=medium, observer=obs, fwd_rad=rad)
216216
```
217217

218218
</details>
@@ -241,7 +241,7 @@ plt.figure(figsize=(4.8, 3.6),dpi=200)
241241
for i, nu in enumerate(bands):
242242
exp = int(np.floor(np.log10(nu)))
243243
base = nu / 10**exp
244-
plt.loglog(times, results['syn'][i,:], label=fr'${base:.1f} \times 10^{{{exp}}}$ Hz')
244+
plt.loglog(times, results.total[i,:], label=fr'${base:.1f} \times 10^{{{exp}}}$ Hz')
245245

246246
def add_note(plt):
247247
plt.annotate('jet break',xy=(3e4, 1e-26), xytext=(3e3, 5e-28), arrowprops=dict(arrowstyle='->'))
@@ -287,7 +287,7 @@ colors = plt.cm.viridis(np.linspace(0,1,len(epochs)))
287287
for i, t in enumerate(epochs):
288288
exp = int(np.floor(np.log10(t)))
289289
base = t / 10**exp
290-
plt.loglog(frequencies, results['syn'][:,i], color=colors[i], label=fr'${base:.1f} \times 10^{{{exp}}}$ s')
290+
plt.loglog(frequencies, results.total[:,i], color=colors[i], label=fr'${base:.1f} \times 10^{{{exp}}}$ s')
291291

292292
# 5. Add vertical lines marking the bands from the light curve plot
293293
for i, band in enumerate(bands):
@@ -323,16 +323,23 @@ frequencies = np.logspace(9, 17, 200)
323323
# For time-frequency pairs (times array must be in ascending order)
324324
results = model.specific_flux_series(times, frequencies)
325325

326-
# The returned results is a dictionary containing arrays of the same shape as the input
327-
print("Result keys:", results.keys()) # e.g., ['syn', 'IC'] depending on your model
328-
print("Shape:", results['syn'].shape) # Same shape as input arrays
326+
# The returned results is a FluxDict object with different flux components
327+
print("Result attributes:", dir(results)) # Shows .fwd, .rvs, .total attributes
328+
print("Total flux shape:", results.total.shape) # Same shape as input arrays
329+
print("Forward shock shape:", results.fwd.sync.shape) # Forward shock synchrotron component
329330
```
330331

331332
**Key differences:**
332333
- `specific_flux()`: Calculates flux on a time-frequency grid (NxM output from N times and M frequencies)
333334
- `specific_flux_series()`: Calculates flux at paired time-frequency points (N output from N time-frequency pairs), requires ascending order time arrays
334335
- `specific_flux_series_with_expo()`: Same as above but with exposure time averaging for realistic observational scenarios
335336

337+
**Return value structure:**
338+
All flux calculation methods return a `FluxDict` object with:
339+
- `.total`: Combined flux from all components
340+
- `.fwd`: Forward shock flux (has `.sync` and `.ssc` attributes)
341+
- `.rvs`: Reverse shock flux (has `.sync` and `.ssc` attributes)
342+
336343
</details>
337344

338345

@@ -360,7 +367,7 @@ obs = Observer(lumi_dist=1e26, z=0.1, theta_obs=0.)
360367

361368
rad = Radiation(eps_e=1e-1, eps_B=1e-3, p=2.3)
362369

363-
model = Model(jet=jet, medium=medium, observer=obs, forward_rad=rad, resolutions=(0.1,5,10))
370+
model = Model(jet=jet, medium=medium, observer=obs, fwd_rad=rad, resolutions=(0.1,5,10))
364371
```
365372

366373
</details>
@@ -376,33 +383,40 @@ Now, let's get the internal simulation quantities:
376383
# Get the simulation details over a time range
377384
details = model.details(t_min=1e0, t_max=1e8)
378385

379-
# Print the keys of the internal quantities
380-
print("Simulation details:", details.keys())
386+
# Print the available attributes
387+
print("Simulation details attributes:", dir(details))
388+
print("Forward shock attributes:", dir(details.fwd))
381389
```
382-
You will get a list of keys representing the internal quantities, such as `t_src`, `t_comv_fwd`, `t_obs_fwd`, etc.
383-
384-
- `phi`: 1D numpy array of azimuthal angles in `radians`.
385-
- `theta`: 1D numpy array of polar angles in `radians`.
386-
- `t_src`: 3D numpy array of source frame times on coordinate (phi_i, theta_j, t_k) grid in `seconds`.
387-
- `t_comv_fwd`: 3D numpy array of comoving times for the forward shock in `seconds`.
388-
- `t_obs_fwd`: 3D numpy array of observer times for the forward shock in `seconds`.
389-
- `Gamma_fwd`: 3D numpy array of downstream Lorentz factors for the forward shock.
390-
- `Gamma_th_fwd`: 3D numpy array of thermal Lorentz factors for the forward shock.
391-
- `r_fwd`: 3D numpy array of lab frame radii in `cm`.
392-
- `B_fwd`: 3D numpy array of downstream comoving magnetic field strengths for the forward shock in `Gauss`.
393-
- `theta_fwd`: 3D numpy array of polar angles for the forward shock in `radians`.
394-
- `N_p_fwd`: 3D numpy array of downstream shocked proton number per solid angle for the forward shock.
395-
- `N_e_fwd`: 3D numpy array of downstream synchrotron electron number per solid angle for the forward shock.
396-
- `gamma_a_fwd`: 3D numpy array of comoving frame self-absorption Lorentz factors for the forward shock.
397-
- `gamma_m_fwd`: 3D numpy array of comoving frame injection Lorentz factors for the forward shock.
398-
- `gamma_c_fwd`: 3D numpy array of comoving frame cooling Lorentz factors for the forward shock.
399-
- `gamma_M_fwd`: 3D numpy array of comoving frame maximum Lorentz factors for the forward shock.
400-
- `nu_a_fwd`: 3D numpy array of comoving frame self-absorption frequencies for the forward shock in `Hz`.
401-
- `nu_m_fwd`: 3D numpy array of comoving frame injection frequencies for the forward shock in `Hz`.
402-
- `nu_c_fwd`: 3D numpy array of comoving frame cooling frequencies for the forward shock in `Hz`.
403-
- `nu_M_fwd`: 3D numpy array of comoving frame maximum frequencies for the forward shock in `Hz`.
404-
- `I_nu_max_fwd`: 3D numpy array of comoving frame synchrotron maximum specific intensities for the forward shock in `erg/cm²/s/Hz`.
405-
- `Doppler_fwd`: 3D numpy array of Doppler factors for the forward shock.
390+
You will get a `SimulationDetails` object with the following structure:
391+
392+
**Main grid coordinates:**
393+
- `details.phi`: 1D numpy array of azimuthal angles in `radians`
394+
- `details.theta`: 1D numpy array of polar angles in `radians`
395+
- `details.t_src`: 3D numpy array of source frame times on coordinate (phi_i, theta_j, t_k) grid in `seconds`
396+
397+
**Forward shock details (accessed via `details.fwd`):**
398+
- `details.fwd.t_comv`: 3D numpy array of comoving times for the forward shock in `seconds`
399+
- `details.fwd.t_obs`: 3D numpy array of observer times for the forward shock in `seconds`
400+
- `details.fwd.Gamma`: 3D numpy array of downstream Lorentz factors for the forward shock
401+
- `details.fwd.Gamma_th`: 3D numpy array of thermal Lorentz factors for the forward shock
402+
- `details.fwd.r`: 3D numpy array of lab frame radii in `cm`
403+
- `details.fwd.B_comv`: 3D numpy array of downstream comoving magnetic field strengths for the forward shock in `Gauss`
404+
- `details.fwd.theta`: 3D numpy array of polar angles for the forward shock in `radians`
405+
- `details.fwd.N_p`: 3D numpy array of downstream shocked proton number per solid angle for the forward shock
406+
- `details.fwd.N_e`: 3D numpy array of downstream synchrotron electron number per solid angle for the forward shock
407+
- `details.fwd.gamma_a`: 3D numpy array of comoving frame self-absorption Lorentz factors for the forward shock
408+
- `details.fwd.gamma_m`: 3D numpy array of comoving frame injection Lorentz factors for the forward shock
409+
- `details.fwd.gamma_c`: 3D numpy array of comoving frame cooling Lorentz factors for the forward shock
410+
- `details.fwd.gamma_M`: 3D numpy array of comoving frame maximum Lorentz factors for the forward shock
411+
- `details.fwd.nu_a`: 3D numpy array of comoving frame self-absorption frequencies for the forward shock in `Hz`
412+
- `details.fwd.nu_m`: 3D numpy array of comoving frame injection frequencies for the forward shock in `Hz`
413+
- `details.fwd.nu_c`: 3D numpy array of comoving frame cooling frequencies for the forward shock in `Hz`
414+
- `details.fwd.nu_M`: 3D numpy array of comoving frame maximum frequencies for the forward shock in `Hz`
415+
- `details.fwd.I_nu_max`: 3D numpy array of comoving frame synchrotron maximum specific intensities for the forward shock in `erg/cm²/s/Hz`
416+
- `details.fwd.Doppler`: 3D numpy array of Doppler factors for the forward shock
417+
418+
**Reverse shock details (accessed via `details.rvs`, if reverse shock is enabled):**
419+
- Similar attributes as forward shock but for the reverse shock component
406420

407421
</details>
408422

@@ -416,23 +430,28 @@ To analyze the temporal evolution of physical parameters across different refere
416430
This code creates a comprehensive multi-panel figure displaying the temporal evolution of fundamental shock parameters (Lorentz factor, magnetic field, particle numbers, radius, and peak synchrotron power) across all three reference frames:
417431

418432
```python
419-
keys =['Gamma_fwd', 'B_fwd', 'N_p_fwd','r_fwd','N_e_fwd','P_nu_max_fwd']
433+
attrs =['Gamma', 'B_comv', 'N_p','r','N_e','I_nu_max']
420434
ylabels = [r'$\Gamma$', r'$B^\prime$ [G]', r'$N_p$', r'$r$ [cm]', r'$N_e$', r'$I_{\nu, \rm max}^\prime$ [erg/s/Hz]']
421435

422-
frames = ['t_src', 't_comv_fwd', 't_obs_fwd']
436+
frames = ['t_src', 't_comv', 't_obs']
423437
titles = ['source frame', 'comoving frame', 'observer frame']
424438
colors = ['C0', 'C1', 'C2']
425439
xlabels = [r'$t_{\rm src}$ [s]', r'$t^\prime$ [s]', r'$t_{\rm obs}$ [s]']
426-
plt.figure(figsize= (4.2*len(frames), 3*len(keys)))
440+
plt.figure(figsize= (4.2*len(frames), 3*len(attrs)))
427441

428442
#plot the evolution of various parameters for phi = 0 and theta = 0 (so the first two indexes are 0)
429443
for i, frame in enumerate(frames):
430-
for j, key in enumerate(keys):
431-
plt.subplot(len(keys), len(frames) , j * len(frames) + i + 1)
444+
for j, attr in enumerate(attrs):
445+
plt.subplot(len(attrs), len(frames) , j * len(frames) + i + 1)
432446
if j == 0:
433447
plt.title(titles[i])
434-
plt.loglog(details[frame][0, 0, :], details[key][0, 0, :], color='k',lw=2.5)
435-
plt.loglog(details[frame][0, 0, :], details[key][0, 0, :], color=colors[i])
448+
value = getattr(details.fwd, attr)
449+
if frame == 't_src':
450+
t = getattr(details, frame)
451+
else:
452+
t = getattr(details.fwd, frame)
453+
plt.loglog(t[0, 0, :], value[0, 0, :], color='k',lw=2.5)
454+
plt.loglog(t[0, 0, :], value[0, 0, :], color=colors[i])
436455

437456
plt.xlabel(xlabels[i])
438457
plt.ylabel(ylabels[j])
@@ -449,18 +468,22 @@ plt.savefig('shock_quantities.png', dpi=300,bbox_inches='tight')
449468
This visualization focuses specifically on the characteristic electron energies (self-absorption, injection, and cooling) across all three reference frames:
450469

451470
```python
452-
frames = ['t_src', 't_comv_fwd', 't_obs_fwd']
471+
frames = ['t_src', 't_comv', 't_obs']
453472
xlabels = [r'$t_{\rm src}$ [s]', r'$t^\prime$ [s]', r'$t_{\rm obs}$ [s]']
454473
plt.figure(figsize= (4.2*len(frames), 3.6))
455474

456475
for i, frame in enumerate(frames):
457476
plt.subplot(1, len(frames), i + 1)
458-
plt.loglog(details[frame][0, 0, :], details['gamma_a_fwd'][0, 0, :],label=r'$\gamma_a^\prime$',c='firebrick')
459-
plt.loglog(details[frame][0, 0, :], details['gamma_m_fwd'][0, 0, :],label=r'$\gamma_m^\prime$',c='yellowgreen')
460-
plt.loglog(details[frame][0, 0, :], details['gamma_c_fwd'][0, 0, :],label=r'$\gamma_c^\prime$',c='royalblue')
461-
plt.loglog(details[frame][0, 0, :], details['gamma_a_fwd'][0, 0, :]*details['Doppler_fwd'][0,0,:],label=r'$\gamma_a$',ls='--',c='firebrick')
462-
plt.loglog(details[frame][0, 0, :], details['gamma_m_fwd'][0, 0, :]*details['Doppler_fwd'][0,0,:],label=r'$\gamma_m$',ls='--',c='yellowgreen')
463-
plt.loglog(details[frame][0, 0, :], details['gamma_c_fwd'][0, 0, :]*details['Doppler_fwd'][0,0,:],label=r'$\gamma_c$',ls='--',c='royalblue')
477+
if frame == 't_src':
478+
t = getattr(details, frame)
479+
else:
480+
t = getattr(details.fwd, frame)
481+
plt.loglog(t[0, 0, :], details.fwd.gamma_a[0, 0, :],label=r'$\gamma_a^\prime$',c='firebrick')
482+
plt.loglog(t[0, 0, :], details.fwd.gamma_m[0, 0, :],label=r'$\gamma_m^\prime$',c='yellowgreen')
483+
plt.loglog(t[0, 0, :], details.fwd.gamma_c[0, 0, :],label=r'$\gamma_c^\prime$',c='royalblue')
484+
plt.loglog(t[0, 0, :], details.fwd.gamma_a[0, 0, :]*details.fwd.Doppler[0,0,:],label=r'$\gamma_a$',ls='--',c='firebrick')
485+
plt.loglog(t[0, 0, :], details.fwd.gamma_m[0, 0, :]*details.fwd.Doppler[0,0,:],label=r'$\gamma_m$',ls='--',c='yellowgreen')
486+
plt.loglog(t[0, 0, :], details.fwd.gamma_c[0, 0, :]*details.fwd.Doppler[0,0,:],label=r'$\gamma_c$',ls='--',c='royalblue')
464487
plt.xlabel(xlabels[i])
465488
plt.ylabel(r'$\gamma_e^\prime$')
466489
plt.legend(ncol=2)
@@ -476,18 +499,22 @@ plt.savefig('electron_quantities.png', dpi=300,bbox_inches='tight')
476499
This analysis tracks the evolution of characteristic synchrotron frequencies:
477500

478501
```python
479-
frames = ['t_src', 't_comv_fwd', 't_obs_fwd']
502+
frames = ['t_src', 't_comv', 't_obs']
480503
xlabels = [r'$t_{\rm src}$ [s]', r'$t^\prime$ [s]', r'$t_{\rm obs}$ [s]']
481504
plt.figure(figsize= (4.2*len(frames), 3.6))
482505

483506
for i, frame in enumerate(frames):
484507
plt.subplot(1, len(frames), i + 1)
485-
plt.loglog(details[frame][0, 0, :], details['nu_a_fwd'][0, 0, :],label=r'$\nu_a^\prime$',c='firebrick')
486-
plt.loglog(details[frame][0, 0, :], details['nu_m_fwd'][0, 0, :],label=r'$\nu_m^\prime$',c='yellowgreen')
487-
plt.loglog(details[frame][0, 0, :], details['nu_c_fwd'][0, 0, :],label=r'$\nu_c^\prime$',c='royalblue')
488-
plt.loglog(details[frame][0, 0, :], details['nu_a_fwd'][0, 0, :]*details['Doppler_fwd'][0,0,:],label=r'$\nu_a$',ls='--',c='firebrick')
489-
plt.loglog(details[frame][0, 0, :], details['nu_m_fwd'][0, 0, :]*details['Doppler_fwd'][0,0,:],label=r'$\nu_m$',ls='--',c='yellowgreen')
490-
plt.loglog(details[frame][0, 0, :], details['nu_c_fwd'][0, 0, :]*details['Doppler_fwd'][0,0,:],label=r'$\nu_c$',ls='--',c='royalblue')
508+
if frame == 't_src':
509+
t = getattr(details, frame)
510+
else:
511+
t = getattr(details.fwd, frame)
512+
plt.loglog(t[0, 0, :], details.fwd.nu_a[0, 0, :],label=r'$\nu_a^\prime$',c='firebrick')
513+
plt.loglog(t[0, 0, :], details.fwd.nu_m[0, 0, :],label=r'$\nu_m^\prime$',c='yellowgreen')
514+
plt.loglog(t[0, 0, :], details.fwd.nu_c[0, 0, :],label=r'$\nu_c^\prime$',c='royalblue')
515+
plt.loglog(t[0, 0, :], details.fwd.nu_a[0, 0, :]*details.fwd.Doppler[0,0,:],label=r'$\nu_a$',ls='--',c='firebrick')
516+
plt.loglog(t[0, 0, :], details.fwd.nu_m[0, 0, :]*details.fwd.Doppler[0,0,:],label=r'$\nu_m$',ls='--',c='yellowgreen')
517+
plt.loglog(t[0, 0, :], details.fwd.nu_c[0, 0, :]*details.fwd.Doppler[0,0,:],label=r'$\nu_c$',ls='--',c='royalblue')
491518
plt.xlabel(xlabels[i])
492519
plt.ylabel(r'$\nu$ [Hz]')
493520
plt.legend(ncol=2)
@@ -505,9 +532,9 @@ This polar plot visualizes the spatial distribution of the Doppler factor across
505532
plt.figure(figsize=(6,6))
506533
ax = plt.subplot(111, polar=True)
507534

508-
theta = details['theta_fwd'][0,:,:]
509-
r = details['r_fwd'][0,:,:]
510-
D = details['Doppler_fwd'][0,:,:]
535+
theta = details.fwd.theta[0,:,:]
536+
r = details.fwd.r[0,:,:]
537+
D = details.fwd.Doppler[0,:,:]
511538

512539
# Polar contour plot
513540
scale = 3.0
@@ -537,9 +564,9 @@ This final visualization maps the equal arrival time surfaces in polar coordinat
537564
plt.figure(figsize=(6,6))
538565
ax = plt.subplot(111, polar=True)
539566

540-
theta = details['theta_fwd'][0,:,:]
541-
r = details['r_fwd'][0,:,:]
542-
t_obs = details['t_obs_fwd'][0,:,:]
567+
theta = details.fwd.theta[0,:,:]
568+
r = details.fwd.r[0,:,:]
569+
t_obs = details.fwd.t_obs[0,:,:]
543570

544571
scale = 3.0
545572
c = ax.contourf(theta*scale, r, np.log10(t_obs), levels=30, cmap='viridis')

0 commit comments

Comments
 (0)