Functional LUME-Astra¶
This is the functional way to run astra and return the evaluate Astra object, or simple dict of outputs
Settings is a list of settings that can appear in the input file.
# Useful for debugging
%load_ext autoreload
%autoreload 2
from astra import run_astra, run_astra_with_generator
import matplotlib.pyplot as plt
import os
Input template file and some settings
ASTRA_IN =  'templates/dcgun/astra.in'
settings0 = {'zstop':1, 'zemit':200, 'zphase':1, 'phases':True}
Run Astra¶
A1 = run_astra(settings0, astra_input_file=ASTRA_IN, verbose=True, timeout=100)
run_astra
zstop is in astra newrun
zstop is in astra output
zemit is in astra newrun
zphase is in astra newrun
phases is in astra newrun
loading 1 particle files
[100.0]
{'start_time': 1690854350.025616, 'run_script': '/Users/chrisonian/Code/Astra/bin/Astra astra.in', 'why_error': '', 'run_time': 0.7370400428771973, 'run_error': False}
Run Astra with Generator¶
GENERATOR_IN = 'templates/dcgun/generator.in'
settings0['ipart']= 2000
A2 = run_astra_with_generator(settings0, astra_input_file=ASTRA_IN,
                              generator_input_file=GENERATOR_IN, verbose=True)
run_astra_with_generator
zstop is in astra newrun
zstop is in astra output
zemit is in astra newrun
zphase is in astra newrun
phases is in astra newrun
ipart is in generator
set spacecharge mesh for n_particles: 2000 to {'nrad': 10, 'nlong_in': 20}
 --------------------------------------------------------------------------
                              generator              
                 Version 1.0 - macOS 64bit - Intel   
                        DESY,  Hamburg 2002          
                        Mon Jul 31 18:45:50 
     Working File is:    generator.in                                      
     Initializing       2000      electrons
     including 6 probe particles at standard positions
     Particles start from a cathode
     Particles are quasi randomly distributed
          WARNING: Values could not be reached:
          Energy spread too high.
                  46 times standard correction procedure
     Final check:
     Particles taken into account      N =       2000
     total charge                      Q =    -0.1000     nC
     horizontal beam position          x =     2.3378E-06 mm
     vertical beam position            y =     8.9462E-06 mm
     longitudinal beam position        z =      0.000     m
     horizontal beam size          sig x =     0.2500     mm
     vertical beam size            sig y =     0.2500     mm
     longitudinal beam size        sig z =      0.000     mm
     total emission time               t =     5.0872E-02 ns
     rms emission time             sig t =     8.3856E-03 ns
     average kinetic energy            E =     1.0197E-06 MeV
     energy spread                    dE =     4.2631E-04 keV
     average momentum                  P =     1.0208E-03 MeV/c
     transverse beam emittance     eps x =     0.1747     pi mrad mm
     correlated divergence         cor x =     6.8371E-03 mrad 
     transverse beam emittance     eps y =     0.1750     pi mrad mm
     correlated divergence         cor y =    -4.4571E-03 mrad
     longitudinal beam emittance   eps z =      0.000     pi keV mm
     correlated energy spread      cor z =      0.000     keV
     emittance ratio eps y/eps x         =     0.9982    
     phase-space distribution saved to file: generator.part                
     Generator ended with     1 warning(s)
Initial particles written to /var/folders/2f/l5_mybzs30j4qqvyj98w1_nw0000gn/T/tmp5xjn8oto/astra.particles
loading 1 particle files
[100.0]
{'start_time': 1690854350.8262599, 'run_script': '/Users/chrisonian/Code/Astra/bin/Astra astra.in', 'why_error': '', 'run_time': 0.7480919361114502, 'run_error': False}
run_astra_with_generator finished
Run Astra with Distgen¶
from astra.astra_distgen import run_astra_with_distgen
DISTGEN_IN =  'templates/dcgun/distgen.yaml'
settings0 = {'zstop':1, 'zemit':200, 'zphase':1, 'phases':True}
settings0['distgen:n_particle'] = 2000
A3 = run_astra_with_distgen(settings0, astra_input_file=ASTRA_IN,
                              distgen_input_file=DISTGEN_IN, verbose=True)
run_astra_with_generator
zstop is in astra newrun
zstop is in astra output
zemit is in astra newrun
zphase is in astra newrun
phases is in astra newrun
Setting distgen n_particle = 2000
Distribution format: None
   Warning: no output file specified, defaulting to "None".
Output file: None
Creating beam distribution....
   Beam starting from: cathode
   Total charge: 100 pC.
   Number of macroparticles: 2000.
   Assuming cylindrical symmetry...
   r distribution: radial uniform
      min_r = 0 mm, max_r = 0.5 mm
   theta distribution: uniform theta
      min_theta = 0 rad, max_theta = 6.28319 rad
   t distribution: Gaussian
      avg_t = 0 ps, sigma_t = 8.500 ps
      Left n_sigma_cutoff = 3, Right n_sigma_cutoff = -3
   px distribution: Gaussian
      avg_px = 0 eV/c, sigma_px = 357.421 eV/c
   py distribution: Gaussian
      avg_py = 0 eV/c, sigma_py = 357.421 eV/c
   pz distribution: Gaussian
      avg_pz = 0 eV/c, sigma_pz = 357.421 eV/c
   Shifting avg_x = -0.000182722 mm -> 0 mm
   Scaling sigma_x = 0.249836 mm -> 0.25 mm
   Shifting avg_y = -5.96585E-05 mm -> 0 mm
   Scaling sigma_y = 0.249997 mm -> 0.25 mm
   Shifting avg_px = -1.43404 eV/c -> 0 eV/c
   Scaling sigma_px = 356.94 eV/c -> 357.421 eV/c
   Shifting avg_py = -0.99808 eV/c -> 0 eV/c
   Scaling sigma_py = 356.407 eV/c -> 357.421 eV/c
   Shifting avg_pz = -2.93972 eV/c -> 0 eV/c
   Scaling sigma_pz = 356.195 eV/c -> 357.421 eV/c
   Shifting avg_t = -0.0272122 ps -> 0 ps
   Scaling sigma_t = 8.36979 ps -> 8.38592 ps
   Cathode start: fixing pz momenta to forward hemisphere
      avg_pz -> 285.455 eV/c, sigma_pz -> 215.094 eV/c
...done. Time Elapsed: 20.7162 ms.
   Created particles in .particles: 
   ParticleGroup with 2000 particles with total charge 9.999999999999999e-11 Cset spacecharge mesh for n_particles: 2000 to {'nrad': 10, 'nlong_in': 20}
Initial particles written to /var/folders/2f/l5_mybzs30j4qqvyj98w1_nw0000gn/T/tmppi727x6e/astra.particles
loading 1 particle files
[100.0]
{'start_time': 1690854351.635436, 'run_script': '/Users/chrisonian/Code/Astra/bin/Astra astra.in', 'why_error': '', 'run_time': 0.7446029186248779, 'run_error': False}
These Generator and Distgen inputs are set up to produce nearly the same initial beams
plt.plot(A2.stat('sigma_x'))
plt.plot(A3.stat('sigma_x'))
[<matplotlib.lines.Line2D at 0x151a1e880>]
Evaluate functions¶
For scans an optimizations, a user often wants to run a simulation many times and examine some particular output. The package provides several evaluate_ functions that are similar to the run_ functions above, but apply some merit function to the output and returns that. Additionally, if an archive_path is provided, the .archive method will be called to save the complete object output
This is the default merit function that is applied. The user can supply a different function if needed.
from astra.evaluate import default_astra_merit
default_astra_merit(A2)
{'error': False,
 'end_mean_z': 1.0,
 'end_mean_t': 4.0153e-09,
 'end_mean_x': 6.1453e-09,
 'end_sigma_x': 0.00046093,
 'end_sigma_xp': 0.00051108,
 'end_norm_emit_x': 1.7455e-07,
 'end_cov_x__xp': 2.1221217199999998e-07,
 'end_mean_y': 3.9381999999999995e-08,
 'end_sigma_y': 0.00046181,
 'end_sigma_yp': 0.0005110700000000001,
 'end_norm_emit_y': 1.7527e-07,
 'end_cov_y__yp': 2.125018715e-07,
 'end_mean_kinetic_energy': 499790.0,
 'end_sigma_z': 0.0021705,
 'end_sigma_energy': 1.5773,
 'end_norm_emit_z': 0.0034225,
 'end_cov_z__energy': 7.868713650000001e-05,
 'end_n_particle_loss': 0,
 'end_total_charge': 9.964999999999999e-11,
 'end_higher_order_energy_spread': 1.5777476779634658}
evaluate_astra_with_generator¶
An even simpler run, returns a simple dict of outputs. For use in optimization
from astra import evaluate_astra_with_generator
MY_GENERATOR_TEMPLATE = 'templates/dcgun/generator.in'
settings0 = {'zstop':1, 'zemit':200, 'zphase':1, 'phases':True}
settings0['ipart'] = 2000
outputs1 = evaluate_astra_with_generator(settings0, 
                                        astra_input_file=ASTRA_IN,
                                        generator_input_file=GENERATOR_IN,
                                        archive_path = '.')
outputs1
{'error': False,
 'end_mean_z': 1.0,
 'end_mean_t': 4.0153e-09,
 'end_mean_x': 6.1453e-09,
 'end_sigma_x': 0.00046093,
 'end_sigma_xp': 0.00051108,
 'end_norm_emit_x': 1.7455e-07,
 'end_cov_x__xp': 2.1221217199999998e-07,
 'end_mean_y': 3.9381999999999995e-08,
 'end_sigma_y': 0.00046181,
 'end_sigma_yp': 0.0005110700000000001,
 'end_norm_emit_y': 1.7527e-07,
 'end_cov_y__yp': 2.125018715e-07,
 'end_mean_kinetic_energy': 499790.0,
 'end_sigma_z': 0.0021705,
 'end_sigma_energy': 1.5773,
 'end_norm_emit_z': 0.0034225,
 'end_cov_z__energy': 7.868713650000001e-05,
 'end_n_particle_loss': 0,
 'end_total_charge': 9.964999999999999e-11,
 'end_higher_order_energy_spread': 1.5777476779634658,
 'fingerprint': '342ec49887deb72ecbf7505f4bda8e25',
 'archive': '/Users/chrisonian/Code/GitHub/lume-astra/docs/examples/342ec49887deb72ecbf7505f4bda8e25.h5'}
The archive can be loaded back:
from astra import Astra
AX = Astra.from_archive(outputs1['archive'])
Check the merit:
default_astra_merit(AX)
{'error': False,
 'end_cov_x__xp': 2.1221217199999998e-07,
 'end_cov_y__yp': 2.125018715e-07,
 'end_cov_z__energy': 7.868713650000001e-05,
 'end_mean_kinetic_energy': 499790.0,
 'end_mean_t': 4.0153e-09,
 'end_mean_x': 6.1453e-09,
 'end_mean_y': 3.9381999999999995e-08,
 'end_mean_z': 1.0,
 'end_norm_emit_x': 1.7455e-07,
 'end_norm_emit_y': 1.7527e-07,
 'end_norm_emit_z': 0.0034225,
 'end_sigma_energy': 1.5773,
 'end_sigma_x': 0.00046093,
 'end_sigma_xp': 0.00051108,
 'end_sigma_y': 0.00046181,
 'end_sigma_yp': 0.0005110700000000001,
 'end_sigma_z': 0.0021705,
 'end_n_particle_loss': 0,
 'end_total_charge': 9.964999999999999e-11,
 'end_higher_order_energy_spread': 1.5777476779634658}
The Generator can also be loaded from the same archive:
from astra import AstraGenerator
G = AstraGenerator.from_archive(outputs1['archive'])
G.input
{'add': False,
 'c_sig_clock': 3,
 'c_sig_ekin': 5,
 'c_sig_px': 5,
 'c_sig_x': 5,
 'c_sig_y': 5,
 'cathode': True,
 'cor_px': 0,
 'cor_py': 0,
 'dist_px': 'g',
 'dist_py': 'g',
 'dist_pz': 'g',
 'dist_x': 'r',
 'dist_y': 'r',
 'dist_z': 'g',
 'fname': 'generator.part',
 'high_res': True,
 'ipart': 2000,
 'n_add': 0,
 'noise_reduc': True,
 'probe': True,
 'q_total': 0.1,
 'ref_clock': 0,
 'ref_ekin': 1e-06,
 'ref_zpos': 0,
 'sig_clock': 0.00849257,
 'sig_ekin': 0.0005,
 'sig_px': 357.7,
 'sig_py': 357.7,
 'sig_x': 0.25,
 'sig_y': 0.25,
 'species': 'electrons'}
# Cleanup
os.remove(outputs1['archive'])
evaluate_astra_with_distgen¶
from astra import evaluate_astra_with_distgen
?evaluate_astra_with_distgen
Signature: evaluate_astra_with_distgen( settings, astra_input_file=None, distgen_input_file=None, workdir=None, astra_bin='$ASTRA_BIN', timeout=2500, verbose=False, auto_set_spacecharge_mesh=True, archive_path=None, merit_f=None, ) Docstring: Similar to run_astra_with_distgen, but returns a flat dict of outputs as processed by merit_f. If no merit_f is given, a default one will be used. See: astra.evaluate.default_astra_merit Will raise an exception if there is an error. File: ~/Code/GitHub/lume-astra/astra/astra_distgen.py Type: function
settings5 = {'zstop':1, 'zemit':200, 'zphase':1, 'phases':True}
settings5['distgen:n_particle'] = 2000
outputs2 = evaluate_astra_with_distgen(settings5, astra_input_file=ASTRA_IN,
                              distgen_input_file=DISTGEN_IN, archive_path='.')
outputs2
{'error': False,
 'end_mean_z': 1.0,
 'end_mean_t': 4.0156e-09,
 'end_mean_x': 7.553300000000001e-11,
 'end_sigma_x': 0.0004619,
 'end_sigma_xp': 0.00051138,
 'end_norm_emit_x': 1.7514e-07,
 'end_cov_x__xp': 2.1275114000000003e-07,
 'end_mean_y': -3.6688e-09,
 'end_sigma_y': 0.00046157,
 'end_sigma_yp': 0.00051168,
 'end_norm_emit_y': 1.7457e-07,
 'end_cov_y__yp': 2.12876084e-07,
 'end_mean_kinetic_energy': 499790.0,
 'end_sigma_z': 0.0021695000000000004,
 'end_sigma_energy': 1.5373999999999999,
 'end_norm_emit_z': 0.0033353,
 'end_cov_z__energy': -2.1510375550000005e-05,
 'end_n_particle_loss': 0,
 'end_total_charge': 9.999999999999999e-11,
 'end_higher_order_energy_spread': 1.5373494617932955,
 'fingerprint': '87298760ea8c8ab1a8d95865f84b07bd',
 'archive': '/Users/chrisonian/Code/GitHub/lume-astra/docs/examples/87298760ea8c8ab1a8d95865f84b07bd.h5'}
from distgen import Generator
G = Generator()
G.load_archive(outputs2['archive'])
#
# Note that there are no particles, this is just the input. 
# Particles are 
G.particles == None
True
# This will essentially recreate evaluate_astra_with_distgen
A = Astra(verbose=False)
A.load_archive(outputs2['archive'])
# Make particles
G.run()
A.initial_particles = G.particles
A.configure()
A.run()
default_astra_merit(A)
No input data specified.
Run Aborted Traceback (most recent call last):
  File "/Users/chrisonian/Code/GitHub/lume-astra/astra/astra.py", line 313, in run_astra
    self.load_output()
  File "/Users/chrisonian/Code/GitHub/lume-astra/astra/astra.py", line 243, in load_output
    assert len(nlist) == 1, f'Stat keys do not all have the same length: {[len(stats[k]) for k in stats]}'
AssertionError: Stat keys do not all have the same length: []
{'error': True}
# Cleanup
os.remove(outputs2['archive'])
# Compare Generator, Distgen. Thee should be similar, but not exactly the same. 
for k in outputs1:
    print(k, outputs1[k], outputs2[k])
error False False end_mean_z 1.0 1.0 end_mean_t 4.0153e-09 4.0156e-09 end_mean_x 6.1453e-09 7.553300000000001e-11 end_sigma_x 0.00046093 0.0004619 end_sigma_xp 0.00051108 0.00051138 end_norm_emit_x 1.7455e-07 1.7514e-07 end_cov_x__xp 2.1221217199999998e-07 2.1275114000000003e-07 end_mean_y 3.9381999999999995e-08 -3.6688e-09 end_sigma_y 0.00046181 0.00046157 end_sigma_yp 0.0005110700000000001 0.00051168 end_norm_emit_y 1.7527e-07 1.7457e-07 end_cov_y__yp 2.125018715e-07 2.12876084e-07 end_mean_kinetic_energy 499790.0 499790.0 end_sigma_z 0.0021705 0.0021695000000000004 end_sigma_energy 1.5773 1.5373999999999999 end_norm_emit_z 0.0034225 0.0033353 end_cov_z__energy 7.868713650000001e-05 -2.1510375550000005e-05 end_n_particle_loss 0 0 end_total_charge 9.964999999999999e-11 9.999999999999999e-11 end_higher_order_energy_spread 1.5777476779634658 1.5373494617932955 fingerprint 342ec49887deb72ecbf7505f4bda8e25 87298760ea8c8ab1a8d95865f84b07bd archive /Users/chrisonian/Code/GitHub/lume-astra/docs/examples/342ec49887deb72ecbf7505f4bda8e25.h5 /Users/chrisonian/Code/GitHub/lume-astra/docs/examples/87298760ea8c8ab1a8d95865f84b07bd.h5