Ejemplo n.º 1
0
 def setUp(self):
     self.field = EMField(np.array([0, 0, 0.0000001], dtype=float),
                          np.array([0.0, 0.00001, 0.0], dtype=float))
     self.proton = Proton(np.array([0, 0, 0], dtype=float),
                          np.array([0, 1000, 0], dtype=float),
                          np.array([0, 0, 0], dtype=float), "Proton")
     self.time = 5
def test_frequency(test_input, expected):
    """
    This function tests that the (sychro)cyclotron frequency is correctly being calculated for both non-relativistic
    and relativistic particle bunches.
    """
    field = EMField([-0.3, 0.1, 0.2],
                    [6 * 10**(-5), -7 * 10**(-5), 8 * 10**(-5)])
    protons = ProtonBunch(100, 1)
    protons.bunch = [test_input]
    field.setFrequency(protons)
    assert expected == pytest.approx(field.frequency, rel=0.001)
def test_adaptiveStep(test_input, expected):
    """
    This will test that the step size in any integrator correctly reduces when any of the particles
    in the bunch are either, in the electric field, or within ±10% of the electric field's
    boundaries.
    """
    deltaT = 100
    protons = ProtonBunch(100, 1)
    protons.bunch[0].position = test_input
    field = EMField(ElectricFieldWidth=[-1, 1])
    assert protons.adaptiveStep(deltaT, field) == expected
def test_velocityVerlet():
    """
    This tests that the velocity Verlet update method is correctly updating a particle's
    position and velocity.
    """
    proton = ChargedParticle(Position=[0,0,0],Velocity=[3000,0,0],Acceleration=[0,-9000,0],Charge=2,Mass=1)
    field = EMField(MagneticField=[0,0,1.5],ElectricFieldWidth=[0,0])
    proton.velocityVerlet(0.1,field,0)
    expected_position = [300., -45., 0.]
    expected_velocity = [2865., -879.75, 0.]
    assert np.array_equal(expected_position,proton.position)
    assert np.allclose(expected_velocity,proton.velocity,atol=0.01)
def test_RungeKutta4():
    """
    This tests that the fourth order Runge-Kutta update method is correctly updating a particle's
    position and velocity.
    """
    proton = ChargedParticle(Position=[0,0,0],Velocity=[3000,0,0],Acceleration=[0,-9000,0],Charge=2,Mass=1)
    field = EMField(MagneticField=[0,0,1.5],ElectricFieldWidth=[0,0])
    proton.RungeKutta4(0.1,field,0)
    expected_position = [295.5, -44.6625, 0.]
    expected_velocity = [2866.0125, -886.5, 0.]
    assert np.allclose(expected_position,proton.position,atol=0.0001)
    assert np.allclose(expected_velocity,proton.velocity,atol=0.01)
 def __init__(self, timestep, totaltime, intmethod, ElectricF, MagneticF,
              BunchSize):
     self.timestep = timestep
     self.totaltime = totaltime
     self.intmethod = intmethod
     self.ElectricF = ElectricF
     self.MagneticF = MagneticF
     self.BunchSize = BunchSize
     Field = EMField(Magnetic=self.MagneticF, Electric=self.ElectricF)
     self.Field = Field
     ParticleBunch = Bunch(self.BunchSize)
     self.Bunch = ParticleBunch
     self.Bunch.CreateBunch()
Ejemplo n.º 7
0
class TestEMField(unittest.TestCase):
    def setUp(self):
        self.field = EMField(np.array([0, 0, 0.0000001], dtype=float),
                             np.array([0.0, 0.00001, 0.0], dtype=float))
        self.proton = Proton(np.array([0, 0, 0], dtype=float),
                             np.array([0, 1000, 0], dtype=float),
                             np.array([0, 0, 0], dtype=float), "Proton")
        self.time = 5

    def test_lorentzaccel(self):
        result = self.field.lorentzaccel(self.proton, self.time)
        expected = np.array([9578.83322415, -667.00632589, 0.0])
        assert (np.isclose(result, expected)).all()
def test_exceedingC():
    """
    This test will check that if the user tries to create a particle whose speed exceeds the speed
    of light in a vacuum, a ValueError is raised. It will then check that if a particle's speed is
    ever equal to or greater than the speed of the light in vacuum, the selected integrator will 
    raise a ValueError.
    """
    with pytest.raises(ValueError):
        Particle('proton', const.m_p, [0,0,0], [300000000,0,0])
    proton = ChargedParticle()
    field = EMField()
    proton.velocity = np.array([3*10**(8),0,0],dtype=float)
    with pytest.raises(ValueError):
        proton.euler(0.1)
    with pytest.raises(ValueError):
        proton.eulerCromer(0.1)
    with pytest.raises(ValueError):
        proton.velocityVerlet(0.1,field,0)
    with pytest.raises(ValueError):
        proton.RungeKutta4(0.1,field,0)
def generate_file(phases):
    field = EMField([500 * 10**3, 0, 0], [0, 0, 2.82], [-0.029, 0.029])
    protons = ProtonBunch(500 * 10**(6), 100)
    inital_bunch = copy.deepcopy(protons)

    deltaT, duration = 10**(-11), 2.78 * 10**(-8) * 10
    timeSeries = []
    positionSpread = []
    energySpread = []
    for _ in range(len(phases)):
        positionSpread.append([])
        energySpread.append([])
        timeSeries.append([])

    log.logger.info('starting simulation')

    for (angle, loop_1, loop_2, loop_3) in zip(phases, positionSpread,
                                               energySpread, timeSeries):
        time = 0
        field.phase = angle  # apply the new phase shift to the electric field
        protons = copy.deepcopy(inital_bunch)  # reset the proton bunch
        log.logger.info('phase currently being investigated: %s radians' %
                        angle)
        while time <= duration:
            dt = protons.adaptiveStep(deltaT, field)
            time += dt
            field.setFrequency(protons)
            field.getAcceleration(protons.bunch, time, dt)
            protons.update(dt, field, time)
            temp_spread = copy.deepcopy(protons.positionSpread())
            temp_energy = copy.deepcopy(protons.energySpread())
            loop_1.append(temp_spread)
            loop_2.append(temp_energy)
            loop_3.append(time)
    log.logger.info('simulation finished')

    log.logger.info('writing to file')
    np.savez('phase_synchro_data',
             time=timeSeries,
             positions=positionSpread,
             energies=energySpread)
    log.logger.info('file written')
    return np.load('phase_synchro_data.npz', allow_pickle=True)
Ejemplo n.º 10
0
def generate_file(phases):
    field = EMField([50000,0,0], [0,0,0.07]) 
    inital_bunch = ProtonBunch(10**(6),100,10**(-12))
    field.setFrequency(inital_bunch)

    deltaT, duration = 10**(-9), 10**(-6)*10
    timeSeries = []
    positionSpread = []
    energySpread = []
    for _ in range(len(phases)):
        positionSpread.append([])
        energySpread.append([])

    log.logger.info('starting simulation')

    for (angle,loop_1,loop_2) in zip(phases,positionSpread,energySpread):
        time = 0
        field.phase = angle # apply the new phase shift to the electric field
        protons = copy.deepcopy(inital_bunch) # reset the proton bunch
        log.logger.info('phase currently being investigated: %s radians' % angle)
        while time <= duration:
            time += deltaT
            if angle == phases[0]:
                timeSeries.append(time)
            field.getAcceleration(protons.bunch, time, deltaT)
            protons.update(deltaT,field,time,2)
            temp_spread = copy.deepcopy(protons.positionSpread())
            temp_energy = copy.deepcopy(protons.energySpread())
            loop_1.append(temp_spread)
            loop_2.append(temp_energy)
    log.logger.info('simulation finished')

    log.logger.info('writing to file')
    np.savez('phase_data', time=timeSeries, positions=positionSpread, energies=energySpread)
    log.logger.info('file written')
    return np.load('phase_data.npz',allow_pickle=True)
Ejemplo n.º 11
0
from ChargedParticle import ChargedParticle
from ProtonBunch import ProtonBunch

"""
This file is an independent file that tests the simulated time period of a proton in a cyclotron against 
the expected time period given by:

T = 2*pi*m / (qB)

If you do not have the csv containing approximately 100 revolutions, the simulation will run and generate
the csv file for you. It will then print the mean time period and its error (one standard deviation) and the
time period predicted by the equation above. Finally it will print, the ratio of the two time periods; the 
simulated time period divided by the theoretical one.
"""

field = EMField([0.1,0,0], [0,0,1.6*10**(-5)])
proton = ChargedParticle('proton', const.m_p, const.e, [0,0,0], [3000,0,0])
protons = ProtonBunch(100,1) # create a random bunch obeject
protons.bunch = [proton] # overwrite bunch atrribute to to remove the pseudorandom characteristics
field.setFrequency(protons)
theoretical_period = 2*const.pi*proton.mass / (proton.charge*field.magneticMag())

def generate_file(proton,field):
    time, deltaT, duration = 0, 10**(-5), 0.0041*100

    timeSeries = []
    data_csv = []
    revolution = 0
    data_csv.append([revolution,time,0,[0,0,0]]) # ensure data always has one element to avoid index error on line 46
    log.logger.info('starting simulation')
    while time <= duration:
import copy
from EMField import EMField
from ProtonBunch import ProtonBunch
"""
This file generates a file called "cyclotron_data.npz" it contains a time series and four lists containing
copies of a proton bunch in a cyclotron at every time value in the time series. These seperate lists were 
updated using different numerical methods.

The numerical methods are:
    Euler
    Euler-Cromer
    Velocity Verlet
    Fourth order Runge-Kutta
"""

field = EMField([500000, 0, 0], [0, 0, 0.07])
protons_1 = ProtonBunch(10**(6), 3)
protons_2 = copy.deepcopy(protons_1)
protons_3 = copy.deepcopy(protons_1)
protons_4 = copy.deepcopy(protons_1)
field.setFrequency(protons_1)

log.logger.info('Initial average kinetic energy: %s eV' %
                protons_1.KineticEnergy())
log.logger.info('Initial average momentum: %s kg m/s' % protons_1.momentum())
log.logger.info('Initial average position %s m' % protons_1.averagePosition())
log.logger.info('Initial bunch position spread: %s m' %
                protons_1.positionSpread())
log.logger.info('Initial bunch energy spread: %s eV' %
                protons_1.energySpread())
from ProtonBunch import ProtonBunch

"""
This file will analyse the how time step effects the accuracy of the simulation. It will record a cyclotron
simulation using velocity Verlet method using three different time steps. It will then plot the fractional 
kinetic energy and momentum against time for each time step.

If you do not have the data file: timestep_data.npz which contains the kinetic energy and momentum data then
the file will be generated for you. I would recommend you reduce the size of the bunch and the simulation's 
duration otherwise the run time will be quite long.
"""

timesteps = [10**(-8), 4.5*10**(-9), 10**(-9)]
step_strings = ['1e-8 s', '5e-9 s', '1e-9 s']
step_dict = {step_strings[i]:timesteps[i] for i in range(len(timesteps))}
field = EMField([0,0,0], [0,0,0.07], [0,0])
protons = ProtonBunch(10**(6),1)
field.setFrequency(protons)

def generate_file(protons,field):
    inital_bunch = copy.deepcopy(protons)

    duration = 10**(-6)*100
    timeSeries = []
    kineticEnergies = []
    momenta = []
    timeSeries = []
    for _ in range(len(timesteps)):
        kineticEnergies.append([])
        momenta.append([])
        timeSeries.append([])
    """
    This function tests that the (sychro)cyclotron frequency is correctly being calculated for both non-relativistic
    and relativistic particle bunches.
    """
    field = EMField([-0.3, 0.1, 0.2],
                    [6 * 10**(-5), -7 * 10**(-5), 8 * 10**(-5)])
    protons = ProtonBunch(100, 1)
    protons.bunch = [test_input]
    field.setFrequency(protons)
    assert expected == pytest.approx(field.frequency, rel=0.001)


@pytest.mark.parametrize(
    'test_input,expected',
    [((ChargedParticle('proton-1', const.m_p, const.e, [0, 0, 0],
                       [2000, 0, 0]), EMField([0.1, 0, 0])), [0.1, 0, 0]),
     ((ChargedParticle('proton-1', const.m_p, const.e, [10, 0, 0],
                       [2000, 0, 0]), EMField([0.1, 0, 0])), [0, 0, 0]),
     ((ChargedParticle('proton-1', const.m_p, const.e, [10, 0, 0],
                       [2000, -4000, 6000]),
       EMField([0, 0, 0],
               [6 * 10**(-5), -7 * 10**(-5), 8 * 10**(-5)])), [0.1, 0.2, 0.1]),
     ((ChargedParticle('proton-1', const.m_p, const.e, [0, 0, 0],
                       [2000, -4000, 6000]),
       EMField([0, 0, 0],
               [6 * 10**(-5), -7 * 10**(-5), 8 * 10**(-5)])), [0, 0, 0])])
def test_getAcceleration(test_input, expected):
    # BUG if you run the tests, they pass as expected but if you debug the tests you get an
    # unbound local error in the EMField getAcceleration method but the tests still pass?
    """
    This function will test the getAcceleration method in the EMField class, it will check that in