Source code for IDSimPy.preprocessing.ion_cloud_generation

# -*- coding: utf-8 -*-

"""
ion_cloud_generation: Generation of ion cloud initialization files
"""

import numpy as np
from IDSimPy.analysis.constants import *


[docs] def write_cloud_file(ion_cloud, filename): """ Writes an ion cloud to an ion cloud file :param ion_cloud: an np.array with the columns: [x pos, y pos, z pos, x velo, y velo, z velo, charge (in elem. charges), mass (in amu)] :type ion_cloud: numpy.Array :param filename: name of the file in which the tabular ion cloud data is written to :type filename: str """ with open(filename, 'w') as file: file.write('#pos x; pos y; pos z; vx; vy; vz; charge; mass_amu; collision diameter (angstroem); TOB\n') for i_ion in range(np.shape(ion_cloud)[0]): line = ion_cloud[i_ion, :] for v in line: file.write(str(v) + ';') file.write('\n')
[docs] def velo_from_kinetic_energy(ke_eV, mass_amu): ke_J = ke_eV * JOULE_PER_EV m_kg = mass_amu * KG_PER_AMU v = np.sqrt(2.0 * ke_J / m_kg) return v
[docs] def random_sphere(radius, n_samples): # http://mathworld.wolfram.com/SpherePointPicking.html z = 2 * np.random.rand(n_samples) - 1 # uniform in -1, 1 t = 2 * np.pi * np.random.rand(n_samples) # uniform in 0, 2*pi x = np.sqrt(1 - z ** 2) * np.cos(t) y = np.sqrt(1 - z ** 2) * np.sin(t) coords = np.transpose(np.vstack([x, y, z])) * radius return coords
[docs] def set_kinetic_energy_in_z_dir(ion_cloud, ke): ion_cloud[:, 5] = velo_from_kinetic_energy(ke, ion_cloud[:, 7]) return ion_cloud
[docs] def add_thermalized_kinetic_energy(ion_cloud, ke): n_ions = np.shape(ion_cloud)[0] thermal_velo_mag = velo_from_kinetic_energy(ke, ion_cloud[:, 7]) thermal_velo = random_sphere(np.transpose([thermal_velo_mag]), n_ions) ion_cloud[:, 3:6] = ion_cloud[:, 3:6] + thermal_velo return ion_cloud
[docs] def define_xy_grid(n_x, n_y, w_x, w_y, o_x, o_y, mass): """ Defines a grid in the x-y direction (z=0) (grid is from -width to width) :param int n_x: ions in x direction :param int n_y: ions in y direction :param float w_x: width in x direction :param float w_y: width in y direction :param float o_x: offset in x direction :param float o_y: offset in y direction :param float mass: the mass of the ions in the grid :return: the ion cloud in an np.array with the structure as expected by write_cloud_file """ x_vec = np.linspace(-w_x, w_x, n_x) + o_x y_vec = np.linspace(-w_y, w_y, n_y) + o_y result = np.zeros([n_x * n_y, 10]) i = 0 for x in x_vec: for y in y_vec: result[i, :] = np.array([x, y, 0, 0, 0, 0, 1, mass, 0.0, 0]) i += 1 return result
[docs] def define_origin_centered_block(n_ions, w_x, w_y, w_z, mass): """ Defines a block of random ions around the coordinate system origin :param int n_ions: the number of ions in the block :param float w_x: the width in x direction :param float w_y: the width in y direction :param float w_z: the width in z direction :param float mass: the mass of the ions (in amu) :return: the ion cloud in an np.array with the structure as expected by write_cloud_file """ positions = np.random.rand(n_ions, 3) velocity = np.zeros([n_ions, 3]) ion_masses = np.zeros([n_ions, 1]) + mass charges = np.zeros([n_ions, 1]) + 1 diameters= np.zeros([n_ions, 1]) time_of_birts = np.zeros([n_ions, 1]) positions[:, 0] = (positions[:, 0] * (2 * w_x)) - w_x positions[:, 1] = (positions[:, 1] * (2 * w_y)) - w_y positions[:, 2] = (positions[:, 2] * (2 * w_z)) - w_z result = np.hstack([positions, velocity, charges, ion_masses, diameters, time_of_birts]) return result
[docs] def define_cylinder_z_dir(n_ions, r, z, charge, mass): """ Defines a cylinder with the cylinder axis parallel to the z-axis and the center of one face of the cylinder on the origin of the coordinate system filled with random ions. The cylinder cross section, a disk, must be filled uniformly with ions, see http://mathworld.wolfram.com/DiskPointPicking.html for details and argument how to do this. :param int n_ions: The number of ions in the cylinder :param float r: Radius of the cylinder :param float z: Height of the cylinder :param float charge: Charge of the ions in the generated cylinder :param float mass: Mass of the ions in the generated cylinder :return: Array with parameters of the particles in the defined cylinder. Columns are: [x,y,z, vx, vy, vz, charge, mass, time of birth] """ R = np.sqrt(np.random.rand(n_ions, 1)) * r phi = np.random.rand(n_ions, 1) * 2 * np.pi Z = np.random.rand(n_ions, 1) * z X = np.cos(phi) * R Y = np.sin(phi) * R V = np.zeros([n_ions, 3]) C = np.zeros([n_ions, 1]) + charge M = np.zeros([n_ions, 1]) + mass DIAM = np.zeros([n_ions, 1]) TOB = np.zeros([n_ions, 1]) result = np.hstack([X, Y, Z, V, C, M, DIAM, TOB]) return result
[docs] def define_cylinder_x_dir(n_ions, r, x, charge, mass): """ Defines a cylinder with the cylinder axis parallel to the x-axis and the center of one face of the cylinder on the origin of the coordinate system filled with random ions The cylinder cross section, a disk, must be filled uniformly with ions, see http://mathworld.wolfram.com/DiskPointPicking.html for details and argument how to do this. :param int n_ions: The number of ions in the cylinder :param float r: the radius of the cylinder :param float x: length ("radius") in x direction :param float charge: Charge of the ions in the generated cylinder :param float mass: Mass of the ions in the generated cylinder :return: Array with parameters of the particles in the defined cylinder. Columns are: [x,y,z, vx, vy, vz, charge, mass, time of birth] """ R = np.sqrt(np.random.rand(n_ions, 1)) * r phi = np.random.rand(n_ions, 1) * 2 * np.pi X = (np.random.rand(n_ions, 1)-0.5) * 2.0 * x Z = np.cos(phi) * R Y = np.sin(phi) * R V = np.zeros([n_ions, 3]) C = np.zeros([n_ions, 1]) + charge M = np.zeros([n_ions, 1]) + mass DIAM = np.zeros([n_ions, 1]) TOB = np.zeros([n_ions, 1]) result = np.hstack([X, Y, Z, V, C, M, DIAM, TOB]) return result