def collision_rate_ion_ion(T_i, n_i, ion_particle, coulomb_log=None, V=None): r""" momentum relaxation ion-ion collision rate From [3]_, equations (2.36) and (2.122) Considering a Maxwellian distribution of "test" ions colliding with a Maxwellian distribution of "field" ions. Note, it is assumed that electrons are present in such numbers as to establish quasineutrality, but the effects of the test ions colliding with them are not considered here. This result is an ion momentum relaxation rate, and is used in many classical transport expressions. It is equivalent to: * 1/tau_i from ref [1]_ eqn (1) pp. #, * 1/tau_i from ref [2]_ eqn (1) pp. #, * nu_i\i_S from ref [2]_ eqn (1) pp. #, Parameters ---------- T_i : ~astropy.units.Quantity The electron temperature of the Maxwellian test ions n_i : ~astropy.units.Quantity The number density of the Maxwellian test ions ion_particle: string String signifying a particle type of the test and field ions, including charge state information. This function assumes the test and field ions are the same species. coulomb_log : float or dimensionless ~astropy.units.Quantity, optional option to specify a Coulomb logarithm of the electrons on the ions. If not specified, the Coulomb log will is calculated using the .transport/Coulomb_logarithm function. References ---------- .. [1] Braginskii .. [2] Formulary .. [3] Callen Chapter 2, http://homepages.cae.wisc.edu/~callen/chap2.pdf """ from plasmapy.physics.transport import Coulomb_logarithm T_i = T_i.to(units.K, equivalencies=units.temperature_energy()) if coulomb_log is not None: coulomb_log_val = coulomb_log else: particles = [ion_particle, ion_particle] coulomb_log_val = Coulomb_logarithm(T_i, n_i, particles, V) Z_i = atomic.integer_charge(ion_particle) m_i = atomic.ion_mass(ion_particle) nu_i = 4 / 3 * np.sqrt(np.pi / m_i) / (4 * np.pi * eps0)**2 * e**4 * \ n_i * Z_i**4 * coulomb_log_val / (k_B * T_i)**1.5 return nu_i.to(1 / units.s)
def __init__(self, T_e, n_e, Z=None, particle='p'): """ Initialize plasma paramters. The most basic description is composition (ion), temperature, density, and ionization. """ self.T_e = T_e self.n_e = n_e self.particle = particle self.Z = grab_charge(particle, Z) # extract mass from particle self.ionMass = ion_mass(self.particle)
def mass_density(density, particle: str = None, z_mean: float = None) -> u.kg / u.m**3: """Utility function to merge two possible inputs for particle charge. Parameters ---------- density : ~astropy.units.Quantity Either a particle density (number of particles per density, in units of 1/m^3) or a mass density (in units of kg/m^3 or equivalent). particle : str, optional Representation of the particle species (e.g., `'p'` for protons, `'D+'` for deuterium, or `'He-4 +1'` for singly ionized helium-4), which defaults to electrons. If no charge state information is provided, then the particles are assumed to be singly charged. z_mean : float An optional float describing the average ionization of a particle species. Raises ------ ValueError If the `density` has units incovertible to either a particle density or a mass density, or if you pass in a number density without a particle. Returns ------- ~astropy.units.Quantity The mass density calculated from all the provided sources of information. """ if density.unit.is_equivalent(u.kg / u.m**3): rho = density elif density.unit.is_equivalent(u.m**-3): if particle: m_i = atomic.ion_mass(particle) Z = grab_charge(particle, z_mean) rho = density * m_i + Z * density * m_e else: raise ValueError( f"You must pass a particle (not {particle}) to calculate the " f"mass density!") else: raise ValueError(f"mass_density accepts either particle (m**-3)" " or mass (kg * m**-3) density, not {density.unit}!") return rho
def _boilerPlate(T, particles, V): """ Some boiler plate code for checking if inputs to functions in collisions.py are good. Also obtains reduced in mass in a 2 particle collision system along with thermal velocity. """ # checking temperature is in correct units T = T.to(u.K, equivalencies=u.temperature_energy()) # extracting particle information if not isinstance(particles, (list, tuple)) or len(particles) != 2: raise ValueError("Particles input must be a " "list or tuple containing representations of two " f"charged particles. Got {particles} instead.") masses = np.zeros(2) * u.kg charges = np.zeros(2) * u.C for particle, i in zip(particles, range(2)): try: masses[i] = ion_mass(particles[i]) except Exception: raise ValueError("Unable to find mass of particle: " f"{particles[i]}.") try: charges[i] = np.abs(e * integer_charge(particles[i])) if charges[i] is None: raise ValueError("Unable to find charge of particle: " f"{particles[i]}.") except Exception: raise ValueError("Unable to find charge of particle: " f"{particles[i]}.") # obtaining reduced mass of 2 particle collision system reduced_mass = masses[0] * masses[1] / (masses[0] + masses[1]) # getting thermal velocity of system if no velocity is given if np.isnan(V): V = np.sqrt(2 * k_B * T / reduced_mass).to(u.m / u.s) _check_relativistic(V, 'V') return T, masses, charges, reduced_mass, V
def gyrofrequency(B, particle='e-', signed=False, Z=None): r"""Calculate the particle gyrofrequency in units of radians per second. Parameters ---------- B : ~astropy.units.Quantity The magnetic field magnitude in units convertible to tesla. particle : str, optional Representation of the particle species (e.g., 'p' for protons, 'D+' for deuterium, or 'He-4 +1' for singly ionized helium-4), which defaults to electrons. If no charge state information is provided, then the particles are assumed to be singly charged. Z : float or ~astropy.units.Quantity, optional The average ionization (arithmetic mean) for a plasma where the a macroscopic description is valid. If this quantity is not given then the atomic charge state (integer) of the ion is used. This is effectively an average gyrofrequency for the plasma where multiple charge states are present, and should not be interpreted as the gyrofrequency for any single particle. If not provided, it defaults to the integer charge of the `particle`. signed : bool, optional The gyrofrequency can be defined as signed (negative for electron, positive for ion). Default is `False` (unsigned, i.e. always positive). Returns ------- omega_c : ~astropy.units.Quantity The particle gyrofrequency in units of radians per second Raises ------ TypeError If the magnetic field is not a `Quantity` or particle is not of an appropriate type ValueError If the magnetic field contains invalid values or particle cannot be used to identify an particle or isotope Warns ----- ~astropy.units.UnitsWarning If units are not provided, SI units are assumed Notes ----- The particle gyrofrequency is the angular frequency of particle gyration around magnetic field lines and is given by: .. math:: \omega_{ci} = \frac{Z e B}{m_i} The particle gyrofrequency is also known as the particle cyclotron frequency or the particle Larmor frequency. The recommended way to convert from angular frequency to frequency is to use an equivalency between cycles per second and Hertz, as Astropy's `dimensionles_angles` equivalency does not account for the factor of 2*pi needed during this conversion. The `dimensionless_angles` equivalency is appropriate when dividing a velocity by an angular frequency to get a length scale. Examples -------- >>> from astropy import units as u >>> gyrofrequency(0.1*u.T) <Quantity 1.75882002e+10 rad / s> >>> gyrofrequency(0.1*u.T, signed=True) <Quantity -1.75882002e+10 rad / s> >>> gyrofrequency(0.01*u.T, 'p') <Quantity 957883.32241481 rad / s> >>> gyrofrequency(0.01*u.T, 'p', signed=True) <Quantity 957883.32241481 rad / s> >>> gyrofrequency(0.01*u.T, particle='T+') <Quantity 319964.54975911 rad / s> >>> omega_ce = gyrofrequency(0.1*u.T) >>> print(omega_ce) 17588200236.02124 rad / s >>> f_ce = omega_ce.to(u.Hz, equivalencies=[(u.cy/u.s, u.Hz)]) >>> print(f_ce) 2799249007.6528206 Hz """ m_i = atomic.ion_mass(particle) Z = grab_charge(particle, Z) if not signed: Z = abs(Z) omega_ci = u.rad * (Z * e * np.abs(B) / m_i).to(1 / u.s) return omega_ci
def collision_rate_ion_ion(T_i, n_i, ion_particle, coulomb_log=None, V=None, coulomb_log_method="classical"): r""" Momentum relaxation ion-ion collision rate From [3]_, equations (2.36) and (2.122) Considering a Maxwellian distribution of "test" ions colliding with a Maxwellian distribution of "field" ions. Note, it is assumed that electrons are present in such numbers as to establish quasineutrality, but the effects of the test ions colliding with them are not considered here. This result is an ion momentum relaxation rate, and is used in many classical transport expressions. It is equivalent to: * 1/tau_i from ref [1]_ eqn (1) pp. #, * 1/tau_i from ref [2]_ eqn (1) pp. #, * nu_i\i_S from ref [2]_ eqn (1) pp. #, Parameters ---------- T_i : ~astropy.units.Quantity The electron temperature of the Maxwellian test ions n_i : ~astropy.units.Quantity The number density of the Maxwellian test ions ion_particle: str String signifying a particle type of the test and field ions, including charge state information. This function assumes the test and field ions are the same species. V : ~astropy.units.Quantity, optional The relative velocity between particles. If not provided, thermal velocity is assumed: :math:`\mu V^2 \sim 2 k_B T` where `mu` is the reduced mass. coulomb_log : float or dimensionless ~astropy.units.Quantity, optional Option to specify a Coulomb logarithm of the electrons on the ions. If not specified, the Coulomb log will is calculated using the ~plasmapy.physics.transport.Coulomb_logarithm function. coulomb_log_method : string, optional Method used for Coulomb logarithm calculation (see that function for more documentation). Choose from "classical" or "GMS-1" to "GMS-6". References ---------- .. [1] Braginskii .. [2] Formulary .. [3] Callen Chapter 2, http://homepages.cae.wisc.edu/~callen/chap2.pdf Examples -------- >>> from astropy import units as u >>> collision_rate_ion_ion(0.1*u.eV, 1e6/u.m**3, 'p') <Quantity 2.97315582e-05 1 / s> >>> collision_rate_ion_ion(100*u.eV, 1e6/u.m**3, 'p') <Quantity 1.43713193e-09 1 / s> >>> collision_rate_ion_ion(100*u.eV, 1e20/u.m**3, 'p') <Quantity 66411.80316364 1 / s> >>> collision_rate_ion_ion(100*u.eV, 1e20/u.m**3, 'p', coulomb_log_method='GMS-1') <Quantity 66407.00859126 1 / s> >>> collision_rate_ion_ion(100*u.eV, 1e20/u.m**3, 'p', V = c/100) <Quantity 6.53577473 1 / s> >>> collision_rate_ion_ion(100*u.eV, 1e20/u.m**3, 'p', coulomb_log=20) <Quantity 95918.76240877 1 / s> """ from plasmapy.physics.transport.collisions import Coulomb_logarithm T_i = T_i.to(u.K, equivalencies=u.temperature_energy()) m_i = atomic.ion_mass(ion_particle) if V is not None: V = V else: # ion thermal velocity (most probable) V = np.sqrt(2 * k_B * T_i / m_i) if coulomb_log is not None: coulomb_log_val = coulomb_log else: particles = [ion_particle, ion_particle] coulomb_log_val = Coulomb_logarithm(T_i, n_i, particles, V, method=coulomb_log_method) Z_i = atomic.integer_charge(ion_particle) # this is the same as b_perp in collisions.py, using most probable thermal velocity for V # and using ion mass instead of reduced mass bperp = (Z_i * e)**2 / (4 * np.pi * eps0 * m_i * V**2) # collisional cross-section sigma = np.pi * (2 * bperp)**2 # collisional frequency with Coulomb logarithm to correct for small angle collisions nu = n_i * sigma * V * coulomb_log_val # this coefficient is the constant that pops out when comparing this definition of # collisional frequency to the one in collisions.py coeff = np.sqrt(8 / np.pi) / 3 # collisional frequency modified by the constant difference nu_i = coeff * nu return nu_i.to(1 / u.s)
def thermal_speed(T, particle="e-", method="most_probable"): r""" Return the most probable speed for a particle within a Maxwellian distribution. Parameters ---------- T : ~astropy.units.Quantity The particle temperature in either kelvin or energy per particle particle : str, optional Representation of the particle species (e.g., `'p'` for protons, `'D+'` for deuterium, or `'He-4 +1'` for singly ionized helium-4), which defaults to electrons. If no charge state information is provided, then the particles are assumed to be singly charged. method : str, optional Method to be used for calculating the thermal speed. Options are `'most_probable'` (default), `'rms'`, and `'mean_magnitude'`. Returns ------- V : ~astropy.units.Quantity particle thermal speed Raises ------ TypeError The particle temperature is not a ~astropy.units.Quantity ~astropy.units.UnitConversionError If the particle temperature is not in units of temperature or energy per particle ValueError The particle temperature is invalid or particle cannot be used to identify an isotope or particle Warns ----- RelativityWarning If the ion sound speed exceeds 5% of the speed of light, or ~astropy.units.UnitsWarning If units are not provided, SI units are assumed. Notes ----- The particle thermal speed is given by: .. math:: V_{th,i} = \sqrt{\frac{2 k_B T_i}{m_i}} This function yields the most probable speed within a distribution function. However, the definition of thermal velocity varies by the square root of two depending on whether or not this velocity absorbs that factor in the expression for a Maxwellian distribution. In particular, the expression given in the NRL Plasma Formulary [1] is a square root of two smaller than the result from this function. Examples -------- >>> from astropy import units as u >>> thermal_speed(5*u.eV, 'p') <Quantity 30949.69018286 m / s> >>> thermal_speed(1e6*u.K, particle='p') <Quantity 128486.55193256 m / s> >>> thermal_speed(5*u.eV) <Quantity 1326205.12123959 m / s> >>> thermal_speed(1e6*u.K) <Quantity 5505693.98842538 m / s> >>> thermal_speed(1e6*u.K, method="rms") <Quantity 6743070.47577549 m / s> >>> thermal_speed(1e6*u.K, method="mean_magnitude") <Quantity 6212510.3969422 m / s> """ T = T.to(u.K, equivalencies=u.temperature_energy()) try: m = atomic.ion_mass(particle) except AtomicError: raise ValueError("Unable to find {particle} mass in thermal_speed") # different methods, as per https://en.wikipedia.org/wiki/Thermal_velocity if method == "most_probable": V = (np.sqrt(2 * k_B * T / m)).to(u.m / u.s) elif method == "rms": V = (np.sqrt(3 * k_B * T / m)).to(u.m / u.s) elif method == "mean_magnitude": V = (np.sqrt(8 * k_B * T / (m * np.pi))).to(u.m / u.s) else: raise ValueError("Method {method} not supported in thermal_speed") return V
def ion_sound_speed(T_e, T_i, gamma_e=1, gamma_i=3, ion='p+', z_mean=None): r""" Return the ion sound speed for an electron-ion plasma. Parameters ---------- T_e : ~astropy.units.Quantity Electron temperature in units of temperature or energy per particle. If this is not given, then the electron temperature is assumed to be zero. T_i : ~astropy.units.Quantity Ion temperature in units of temperature or energy per particle. If this is not given, then the ion temperature is assumed to be zero. gamma_e : float or int The adiabatic index for electrons, which defaults to 1. This value assumes that the electrons are able to equalize their temperature rapidly enough that the electrons are effectively isothermal. gamma_i : float or int The adiabatic index for ions, which defaults to 3. This value assumes that ion motion has only one degree of freedom, namely along magnetic field lines. ion : str, optional Representation of the ion species (e.g., `'p'` for protons, `'D+'` for deuterium, or 'He-4 +1' for singly ionized helium-4), which defaults to protons. If no charge state information is provided, then the ions are assumed to be singly charged. z_mean : ~astropy.units.Quantity, optional The average ionization (arithmetic mean) for a plasma where the a macroscopic description is valid. If this quantity is not given then the atomic charge state (integer) of the ion is used. This is effectively an average ion sound speed for the plasma where multiple charge states are present. Returns ------- V_S : ~astropy.units.Quantity The ion sound speed in units of meters per second. Raises ------ TypeError If any of the arguments are not entered as keyword arguments or are of an incorrect type. ValueError If the ion mass, adiabatic index, or temperature are invalid. ~plasmapy.utils.PhysicsError If an adiabatic index is less than one. ~astropy.units.UnitConversionError If the temperature is in incorrect units. Warns ----- RelativityWarning If the ion sound speed exceeds 5% of the speed of light. ~astropy.units.UnitsWarning If units are not provided, SI units are assumed. Notes ----- The ion sound speed :math:`V_S` is approximately given by .. math:: V_S = \sqrt{\frac{\gamma_e Z k_B T_e + \gamma_i k_B T_i}{m_i}} where :math:`\gamma_e` and :math:`\gamma_i` are the electron and ion adiabatic indices, :math:`k_B` is the Boltzmann constant, :math:`T_e` and :math:`T_i` are the electron and ion temperatures, :math:`Z` is the charge state of the ion, and :math:`m_i` is the ion mass. This function assumes that the product of the wavenumber and the Debye length is small. In this limit, the ion sound speed is not dispersive. In other words, it is frequency independent. When the electron temperature is much greater than the ion temperature, the ion sound velocity reduces to :math:`\sqrt{\gamma_e k_B T_e / m_i}`. Ion acoustic waves can therefore occur even when the ion temperature is zero. Example ------- >>> from astropy import units as u >>> ion_sound_speed(T_e=5e6*u.K, T_i=0*u.K, ion='p', gamma_e=1, gamma_i=3) <Quantity 203155.0764042 m / s> >>> ion_sound_speed(T_e=5e6*u.K, T_i=0*u.K) <Quantity 203155.0764042 m / s> >>> ion_sound_speed(T_e=500*u.eV, T_i=200*u.eV, ion='D+') <Quantity 229586.01860212 m / s> """ m_i = atomic.ion_mass(ion) Z = grab_charge(ion, z_mean) for gamma, particles in zip([gamma_e, gamma_i], ["electrons", "ions"]): if not isinstance(gamma, (float, int)): raise TypeError( f"The adiabatic index gamma for {particles} must be " "a float or int") if gamma < 1: raise utils.PhysicsError( f"The adiabatic index for {particles} must be between " "one and infinity") T_i = T_i.to(u.K, equivalencies=u.temperature_energy()) T_e = T_e.to(u.K, equivalencies=u.temperature_energy()) try: V_S_squared = (gamma_e * Z * k_B * T_e + gamma_i * k_B * T_i) / m_i V_S = np.sqrt(V_S_squared).to(u.m / u.s) except Exception: raise ValueError("Unable to find ion sound speed.") return V_S
def plasma_frequency(n, particle='e-', z_mean=None): r"""Calculate the particle plasma frequency. Parameters ---------- n : ~astropy.units.Quantity Particle number density in units convertible to per cubic meter particle : str, optional Representation of the particle species (e.g., 'p' for protons, 'D+' for deuterium, or 'He-4 +1' for singly ionized helium-4), which defaults to electrons. If no charge state information is provided, then the particles are assumed to be singly charged. z_mean : ~astropy.units.Quantity, optional The average ionization (arithmetic mean) for a plasma where the a macroscopic description is valid. If this quantity is not given then the atomic charge state (`int`) of the ion is used. This is effectively an average plasma frequency for the plasma where multiple charge states are present. Returns ------- omega_p : ~astropy.units.Quantity The particle plasma frequency in radians per second. Raises ------ TypeError If n_i is not a `~astropy.units.Quantity` or particle is not of an appropriate type. UnitConversionError If `n_i` is not in correct units ValueError If `n_i` contains invalid values or particle cannot be used to identify an particle or isotope. Warns ----- ~astropy.units.UnitsWarning If units are not provided, SI units are assumed Notes ----- The particle plasma frequency is .. math:: \omega_{pi} = Z e \sqrt{\frac{n_i}{\epsilon_0 m_i}} At present, astropy.units does not allow direct conversions from radians/second for angular frequency to 1/second or Hz for frequency. The dimensionless_angles equivalency allows that conversion, but does not account for the factor of 2*pi. The alternatives are to convert to cycle/second or to do the conversion manually, as shown in the examples. Example ------- >>> from astropy import units as u >>> plasma_frequency(1e19*u.m**-3, particle='p') <Quantity 4.16329453e+09 rad / s> >>> plasma_frequency(1e19*u.m**-3, particle='D+') <Quantity 2.94462452e+09 rad / s> >>> plasma_frequency(1e19*u.m**-3) <Quantity 1.78398636e+11 rad / s> """ try: m = atomic.ion_mass(particle) if z_mean is None: # warnings.warn("No z_mean given, defaulting to atomic charge", # PhysicsWarning) try: Z = atomic.integer_charge(particle) except Exception: Z = 1 else: # using user provided average ionization Z = z_mean Z = np.abs(Z) # TODO REPLACE WITH Z = np.abs(grab_charge(particle, z_mean)), some bugs atm except Exception: raise ValueError(f"Invalid particle, {particle}, in " "plasma_frequency.") omega_p = u.rad * Z * e * np.sqrt(n / (eps0 * m)) return omega_p.si
def deBroglie_wavelength(V, particle): r""" Calculates the de Broglie wavelength. Parameters ---------- V : ~astropy.units.Quantity Particle velocity in units convertible to meters per second. particle : str or ~astropy.units.Quantity Representation of the particle species (e.g., `'e'`, `'p'`, `'D+'`, or `'He-4 1+'`, or the particle mass in units convertible to kilograms. Returns ------- lambda_dB : ~astropy.units.Quantity The de Broglie wavelength in units of meters. Raises ------ TypeError The velocity is not a `~astropy.units.Quantity` and cannot be converted into a ~astropy.units.Quantity. ~astropy.units.UnitConversionError If the velocity is not in appropriate units. ~plasmapy.utils.RelativityError If the magnitude of `V` is faster than the speed of light. Warns ----- UserWarning If `V` is not a `~astropy.units.Quantity`, then a `UserWarning` will be raised and units of meters per second will be assumed. Notes ----- The de Broglie wavelength is given by .. math:: \lambda_{dB} = \frac{h}{p} = \frac{h}{\gamma m V} where :math:`h` is the Planck constant, :math:`p` is the relativistic momentum of the particle, :math:`gamma` is the Lorentz factor, :math:`m` is the particle's mass, and :math:`V` is the particle's velocity. Examples -------- >>> from astropy import units as u >>> velocity = 1.4e7*u.m/u.s >>> deBroglie_wavelength(velocity, 'e') <Quantity 5.18997095e-11 m> >>> deBroglie_wavelength(V = 0*u.m/u.s, particle = 'D+') <Quantity inf m> """ utils._check_quantity(V, 'V', 'deBroglie_wavelength', u.m / u.s) V = np.abs(V) if np.any(V >= c): raise utils.RelativityError( "Velocity input in deBroglie_wavelength cannot " "be greater than or equal to the speed of " "light.") if not isinstance(particle, u.Quantity): try: # TODO: Replace with more general routine! m = atomic.ion_mass(particle) except Exception: raise ValueError("Unable to find particle mass.") else: try: m = particle.to(u.kg) except Exception: raise u.UnitConversionError("The second argument for deBroglie" " wavelength must be either a " "representation of a particle or a" " Quantity with units of mass.") if V.size > 1: lambda_dBr = np.ones(V.shape) * np.inf * u.m indices = V.value != 0 lambda_dBr[indices] = h / (m * V[indices] * Lorentz_factor(V[indices])) else: if V == 0 * u.m / u.s: lambda_dBr = np.inf * u.m else: lambda_dBr = h / (Lorentz_factor(V) * m * V) return lambda_dBr.to(u.m)
def deBroglie_wavelength(V, particle): r""" Calculates the de Broglie wavelength. Parameters ---------- V : ~astropy.units.Quantity Particle velocity in units convertible to meters per second. particle : str or ~astropy.units.Quantity Representation of the particle species (e.g., `'e'`, `'p'`, `'D+'`, or `'He-4 1+'`, or the particle mass in units convertible to kilograms. Returns ------- lambda_dB : ~astropy.units.Quantity The de Broglie wavelength in units of meters. Raises ------ TypeError The velocity is not a `~astropy.units.Quantity` and cannot be converted into a ~astropy.units.Quantity. ~astropy.units.UnitConversionError If the velocity is not in appropriate units. ~plasmapy.utils.RelativityError If the magnitude of `V` is faster than the speed of light. Warns ----- ~astropy.units.UnitsWarning If units are not provided, SI units are assumed Notes ----- The de Broglie wavelength is given by .. math:: \lambda_{dB} = \frac{h}{p} = \frac{h}{\gamma m V} where :math:`h` is the Planck constant, :math:`p` is the relativistic momentum of the particle, :math:`gamma` is the Lorentz factor, :math:`m` is the particle's mass, and :math:`V` is the particle's velocity. Examples -------- >>> from astropy import units as u >>> velocity = 1.4e7*u.m/u.s >>> deBroglie_wavelength(velocity, 'e') <Quantity 5.18997095e-11 m> >>> deBroglie_wavelength(V = 0*u.m/u.s, particle = 'D+') <Quantity inf m> """ utils._check_quantity(V, 'V', 'deBroglie_wavelength', u.m / u.s) V = np.abs(V) if np.any(V >= c): raise utils.RelativityError( "Velocity input in deBroglie_wavelength cannot " "be greater than or equal to the speed of " "light.") if not isinstance(particle, u.Quantity): try: # TODO: Replace with more general routine! m = atomic.ion_mass(particle) except Exception: raise ValueError("Unable to find particle mass.") else: try: m = particle.to(u.kg) except Exception: raise u.UnitConversionError("The second argument for deBroglie" " wavelength must be either a " "representation of a particle or a" " Quantity with units of mass.") if V.size > 1: lambda_dBr = np.ones(V.shape) * np.inf * u.m indices = V.value != 0 lambda_dBr[indices] = h / (m * V[indices] * Lorentz_factor(V[indices])) else: if V == 0 * u.m / u.s: lambda_dBr = np.inf * u.m else: lambda_dBr = h / (Lorentz_factor(V) * m * V) return lambda_dBr.to(u.m)
def Alfven_speed(B, density, ion="p+", z_mean=None): r""" Returns the Alfven speed. Parameters ---------- B : ~astropy.units.Quantity The magnetic field magnitude in units convertible to tesla. density : ~astropy.units.Quantity Either the ion number density in units convertible to 1 / m**3, or the mass density in units convertible to kg / m**3. ion : str, optional Representation of the ion species (e.g., `'p'` for protons, `'D+'` for deuterium, or `'He-4 +1'` for singly ionized helium-4), which defaults to protons. If no charge state information is provided, then the ions are assumed to be singly charged. z_mean : ~astropy.units.Quantity, optional The average ionization (arithmetic mean) for a plasma where the a macroscopic description is valid. If this quantity is not given then the atomic charge state (integer) of the ion is used. This is effectively an average Alfven speed for the plasma where multiple charge states are present. Returns ------- V_A : ~astropy.units.Quantity with units of velocity The Alfven velocity of the plasma in units of meters per second. Raises ------ TypeError The magnetic field and density arguments are not Quantities and cannot be converted into Quantities. ~astropy.units.UnitConversionError If the magnetic field or density is not in appropriate units. ~plasmapy.utils.RelativityError If the Alfven velocity is greater than or equal to the speed of light ValueError If the density is negative, or the ion mass or charge state cannot be found. UserWarning if units are not provided and SI units are assumed. Warns ----- ~plasmapy.utils.RelativityWarning If the Alfven velocity exceeds 10% of the speed of light Notes ----- The Alfven velocity :math:`V_A` is the typical propagation speed of magnetic disturbances in a plasma, and is given by: .. math:: V_A = \frac{B}{\sqrt{\mu_0\rho}} where the mass density is :math:`\rho = n_i m_i + n_e m_e`. This expression does not account for relativistic effects, and loses validity when the resulting speed is a significant fraction of the speed of light. This function switches B and density when B has units of number density or mass density and density has units of magnetic field strength. Examples -------- >>> from astropy import units as u >>> from plasmapy.constants import m_p, m_e >>> B = 0.014*u.T >>> n = 5e19*u.m**-3 >>> rho = n*(m_p+m_e) >>> ion = 'p' >>> Alfven_speed(B, n, ion) <Quantity 43173.87029559 m / s> >>> Alfven_speed(B, rho, ion) <Quantity 43173.87029559 m / s> >>> Alfven_speed(B, rho, ion).to(u.cm/u.us) <Quantity 4.31738703 cm / us> """ utils._check_quantity(B, 'B', 'Alfven_speed', u.T) utils._check_quantity(density, 'density', 'Alfven_speed', [u.m**-3, u.kg / u.m**3], can_be_negative=False) B = B.to(u.T) density = density.si if density.unit == u.m**-3: try: m_i = atomic.ion_mass(ion) if z_mean is None: # warnings.warn("No z_mean given, defaulting to atomic charge", # PhysicsWarning) try: Z = atomic.integer_charge(ion) except AtomicError: Z = 1 else: # using average ionization provided by user Z = z_mean # ensuring positive value of Z Z = np.abs(Z) except AtomicError: raise ValueError("Invalid ion in Alfven_speed.") rho = density * m_i + Z * density * m_e elif density.unit == u.kg / u.m**3: rho = density try: V_A = (np.abs(B) / np.sqrt(mu0 * rho)).to(u.m / u.s) except Exception: raise ValueError("Unable to find Alfven speed") return V_A
def ion_sound_speed(*ignore, T_e=0 * units.K, T_i=0 * units.K, gamma_e=1, gamma_i=3, ion='p', z_mean=None): r""" Returns the ion sound speed for an electron-ion plasma. Parameters ---------- T_e : ~astropy.units.Quantity, optional Electron temperature in units of temperature or energy per particle. If this is not given, then the electron temperature is assumed to be zero. If only one temperature is entered, it is assumed to be the electron temperature. T_i : ~astropy.units.Quantity, optional Ion temperature in units of temperature or energy per particle. If this is not given, then the ion temperature is assumed to be zero. gamma_e : float or int The adiabatic index for electrons, which defaults to 1. This value assumes that the electrons are able to equalize their temperature rapidly enough that the electrons are effectively isothermal. gamma_i : float or int The adiabatic index for ions, which defaults to 3. This value assumes that ion motion has only one degree of freedom, namely along magnetic field lines. ion : string, optional Representation of the ion species (e.g., 'p' for protons, 'D+' for deuterium, or 'He-4 +1' for singly ionized helium-4), which defaults to protons. If no charge state information is provided, then the ions are assumed to be singly charged. z_mean : Quantity, optional The average ionization (arithmetic mean) for a plasma where the a macroscopic description is valid. If this quantity is not given then the atomic charge state (integer) of the ion is used. This is effectively an average ion sound speed for the plasma where multiple charge states are present. Returns ------- V_S : ~astropy.units.Quantity The ion sound speed in units of meters per second. Raises ------ TypeError If any of the arguments are not entered as keyword arguments or are of an incorrect type. ValueError If the ion mass, adiabatic index, or temperature are invalid. plasmapy.utils.PhysicsError If an adiabatic index is less than one. units.UnitConversionError If the temperature is in incorrect units. UserWarning If the ion sound speed exceeds 10% of the speed of light, or if units are not provided and SI units are assumed. Notes ----- The ion sound speed :math:`V_S` is approximately given by .. math:: V_S = \sqrt{\frac{\gamma_e Z k_B T_e + \gamma_i k_B T_i}{m_i}} where :math:`\gamma_e` and :math:`\gamma_i` are the electron and ion adiabatic indices, :math:`k_B` is the Boltzmann constant, :math:`T_e` and :math:`T_i` are the electron and ion temperatures, :math:`Z` is the charge state of the ion, and :math:`m_i` is the ion mass. This function assumes that the product of the wavenumber and the Debye length is small. In this limit, the ion sound speed is not dispersive (e.g., frequency independent). When the electron temperature is much greater than the ion temperature, the ion sound velocity reduces to :math:`\sqrt{\gamma_e k_B T_e / m_i}`. Ion acoustic waves can therefore occur even when the ion temperature is zero. Example ------- >>> from astropy import units as u >>> ion_sound_speed(T_e=5e6*u.K, T_i=0*u.K, ion='p', gamma_e=1, gamma_i=3) <Quantity 203155.0764042 m / s> >>> ion_sound_speed(T_e=5e6*u.K) <Quantity 203155.0764042 m / s> >>> ion_sound_speed(T_e=500*u.eV, T_i=200*u.eV, ion='D+') <Quantity 229586.01860212 m / s> """ if ignore: raise TypeError("All arguments are required to be keyword arguments " "in ion_sound_speed to prevent mixing up the electron " "and ion temperatures. An example call that uses the " "units subpackage from astropy is: " "ion_sound_speed(T_e=5*units.K, T_i=0*units.K, " "ion='D+')") try: m_i = atomic.ion_mass(ion) if z_mean is None: # warnings.warn("No z_mean given, defaulting to atomic charge", # PhysicsWarning) try: Z = atomic.integer_charge(ion) except AtomicError: Z = 1 else: # using average ionization provided by user Z = z_mean except AtomicError: raise ValueError("Invalid ion in ion_sound_speed.") if not isinstance(gamma_e, (float, int)): raise TypeError("The adiabatic index for electrons (gamma_e) must be " "a float or int in ion_sound_speed") if not isinstance(gamma_i, (float, int)): raise TypeError("The adiabatic index for ions (gamma_i) must be " "a float or int in ion_sound_speed") if not 1 <= gamma_e <= np.inf: raise utils.PhysicsError( "The adiabatic index for electrons must be between " "one and infinity") if not 1 <= gamma_i <= np.inf: raise utils.PhysicsError( "The adiabatic index for ions must be between " "one and infinity") T_i = T_i.to(units.K, equivalencies=units.temperature_energy()) T_e = T_e.to(units.K, equivalencies=units.temperature_energy()) try: V_S_squared = (gamma_e * Z * k_B * T_e + gamma_i * k_B * T_i) / m_i V_S = np.sqrt(V_S_squared).to(units.m / units.s) except Exception: raise ValueError("Unable to find ion sound speed.") return V_S