From 6b52bb51e94e4ee170a7ce71a22078569cfb29fe Mon Sep 17 00:00:00 2001 From: Dave Grote Date: Fri, 26 Jul 2019 17:44:26 -0700 Subject: In picmi, wrapped the constants in a class --- Python/pywarpx/picmi.py | 96 +++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 47 deletions(-) (limited to 'Python/pywarpx/picmi.py') diff --git a/Python/pywarpx/picmi.py b/Python/pywarpx/picmi.py index ac272089c..fa72893d2 100644 --- a/Python/pywarpx/picmi.py +++ b/Python/pywarpx/picmi.py @@ -7,13 +7,15 @@ import pywarpx codename = 'warpx' picmistandard.register_codename(codename) -# --- Values from WarpXConst.H -c = 299792458. -ep0 = 8.854187817e-12 -mu0 = 1.2566370614359173e-06 -q_e = 1.602176462e-19 -m_e = 9.10938291e-31 -m_p = 1.6726231e-27 +class constants: + # --- Put the constants in their own namespace + # --- Values from WarpXConst.H + c = 299792458. + ep0 = 8.854187817e-12 + mu0 = 1.2566370614359173e-06 + q_e = 1.602176462e-19 + m_e = 9.10938291e-31 + m_p = 1.6726231e-27 class Species(picmistandard.PICMI_Species): @@ -75,9 +77,9 @@ class GaussianBunchDistribution(picmistandard.PICMI_GaussianBunchDistribution): # --- Calculate the total charge. Note that charge might be a string instead of a number. charge = species.charge if charge == 'q_e' or charge == '+q_e': - charge = q_e + charge = constants.q_e elif charge == '-q_e': - charge = -q_e + charge = -constants.q_e species.q_tot = self.n_physical_particles*charge # --- These need to be defined even though they are not used @@ -97,22 +99,22 @@ class GaussianBunchDistribution(picmistandard.PICMI_GaussianBunchDistribution): # --- Note that WarpX takes gamma*beta as input if np.any(np.not_equal(self.velocity_divergence, 0.)): species.momentum_distribution_type = "radial_expansion" - species.u_over_r = self.velocity_divergence[0]/c - #species.u_over_y = self.velocity_divergence[1]/c - #species.u_over_z = self.velocity_divergence[2]/c + species.u_over_r = self.velocity_divergence[0]/constants.c + #species.u_over_y = self.velocity_divergence[1]/constants.c + #species.u_over_z = self.velocity_divergence[2]/constants.c elif np.any(np.not_equal(self.rms_velocity, 0.)): species.momentum_distribution_type = "gaussian" - species.ux_m = self.centroid_velocity[0]/c - species.uy_m = self.centroid_velocity[1]/c - species.uz_m = self.centroid_velocity[2]/c - species.ux_th = self.rms_velocity[0]/c - species.uy_th = self.rms_velocity[1]/c - species.uz_th = self.rms_velocity[2]/c + species.ux_m = self.centroid_velocity[0]/constants.c + species.uy_m = self.centroid_velocity[1]/constants.c + species.uz_m = self.centroid_velocity[2]/constants.c + species.ux_th = self.rms_velocity[0]/constants.c + species.uy_th = self.rms_velocity[1]/constants.c + species.uz_th = self.rms_velocity[2]/constants.c else: species.momentum_distribution_type = "constant" - species.ux = self.centroid_velocity[0]/c - species.uy = self.centroid_velocity[1]/c - species.uz = self.centroid_velocity[2]/c + species.ux = self.centroid_velocity[0]/constants.c + species.uy = self.centroid_velocity[1]/constants.c + species.uz = self.centroid_velocity[2]/constants.c class UniformDistribution(picmistandard.PICMI_UniformDistribution): @@ -143,17 +145,17 @@ class UniformDistribution(picmistandard.PICMI_UniformDistribution): # --- Note that WarpX takes gamma*beta as input if np.any(np.not_equal(self.rms_velocity, 0.)): species.momentum_distribution_type = "gaussian" - species.ux_m = self.directed_velocity[0]/c - species.uy_m = self.directed_velocity[1]/c - species.uz_m = self.directed_velocity[2]/c - species.ux_th = self.rms_velocity[0]/c - species.uy_th = self.rms_velocity[1]/c - species.uz_th = self.rms_velocity[2]/c + species.ux_m = self.directed_velocity[0]/constants.c + species.uy_m = self.directed_velocity[1]/constants.c + species.uz_m = self.directed_velocity[2]/constants.c + species.ux_th = self.rms_velocity[0]/constants.c + species.uy_th = self.rms_velocity[1]/constants.c + species.uz_th = self.rms_velocity[2]/constants.c else: species.momentum_distribution_type = "constant" - species.ux = self.directed_velocity[0]/c - species.uy = self.directed_velocity[1]/c - species.uz = self.directed_velocity[2]/c + species.ux = self.directed_velocity[0]/constants.c + species.uy = self.directed_velocity[1]/constants.c + species.uz = self.directed_velocity[2]/constants.c if self.fill_in: species.do_continuous_injection = 1 @@ -190,17 +192,17 @@ class AnalyticDistribution(picmistandard.PICMI_AnalyticDistribution): # --- Note that WarpX takes gamma*beta as input if np.any(np.not_equal(self.rms_velocity, 0.)): species.momentum_distribution_type = "gaussian" - species.ux_m = self.directed_velocity[0]/c - species.uy_m = self.directed_velocity[1]/c - species.uz_m = self.directed_velocity[2]/c - species.ux_th = self.rms_velocity[0]/c - species.uy_th = self.rms_velocity[1]/c - species.uz_th = self.rms_velocity[2]/c + species.ux_m = self.directed_velocity[0]/constants.c + species.uy_m = self.directed_velocity[1]/constants.c + species.uz_m = self.directed_velocity[2]/constants.c + species.ux_th = self.rms_velocity[0]/constants.c + species.uy_th = self.rms_velocity[1]/constants.c + species.uz_th = self.rms_velocity[2]/constants.c else: species.momentum_distribution_type = "constant" - species.ux = self.directed_velocity[0]/c - species.uy = self.directed_velocity[1]/c - species.uz = self.directed_velocity[2]/c + species.ux = self.directed_velocity[0]/constants.c + species.uy = self.directed_velocity[1]/constants.c + species.uz = self.directed_velocity[2]/constants.c if self.fill_in: species.do_continuous_injection = 1 @@ -216,7 +218,7 @@ class ParticleListDistribution(picmistandard.PICMI_ParticleListDistribution): species.injection_style = "singleparticle" species.single_particle_pos = [self.x[0], self.y[0], self.z[0]] - species.single_particle_vel = [self.ux[0]/c, self.uy[0]/c, self.uz[0]/c] + species.single_particle_vel = [self.ux[0]/constants.c, self.uy[0]/constants.c, self.uz[0]/constants.c] species.single_particle_weight = self.weight # --- These need to be defined even though they are not used @@ -273,7 +275,7 @@ class CylindricalGrid(picmistandard.PICMI_CylindricalGrid): raise Exception('In cylindrical coordinates, a moving window in r can not be done') if self.moving_window_velocity[1] != 0.: pywarpx.warpx.moving_window_dir = 'z' - pywarpx.warpx.moving_window_v = self.moving_window_velocity[1]/c # in units of the speed of light + pywarpx.warpx.moving_window_v = self.moving_window_velocity[1]/constants.c # in units of the speed of light if self.refined_regions: assert len(self.refined_regions) == 1, Exception('WarpX only supports one refined region.') @@ -308,10 +310,10 @@ class Cartesian2DGrid(picmistandard.PICMI_Cartesian2DGrid): pywarpx.warpx.do_moving_window = 1 if self.moving_window_velocity[0] != 0.: pywarpx.warpx.moving_window_dir = 'x' - pywarpx.warpx.moving_window_v = self.moving_window_velocity[0]/c # in units of the speed of light + pywarpx.warpx.moving_window_v = self.moving_window_velocity[0]/constants.c # in units of the speed of light if self.moving_window_velocity[1] != 0.: pywarpx.warpx.moving_window_dir = 'y' - pywarpx.warpx.moving_window_v = self.moving_window_velocity[1]/c # in units of the speed of light + pywarpx.warpx.moving_window_v = self.moving_window_velocity[1]/constants.c # in units of the speed of light if self.refined_regions: assert len(self.refined_regions) == 1, Exception('WarpX only supports one refined region.') @@ -348,13 +350,13 @@ class Cartesian3DGrid(picmistandard.PICMI_Cartesian3DGrid): pywarpx.warpx.do_moving_window = 1 if self.moving_window_velocity[0] != 0.: pywarpx.warpx.moving_window_dir = 'x' - pywarpx.warpx.moving_window_v = self.moving_window_velocity[0]/c # in units of the speed of light + pywarpx.warpx.moving_window_v = self.moving_window_velocity[0]/constants.c # in units of the speed of light if self.moving_window_velocity[1] != 0.: pywarpx.warpx.moving_window_dir = 'y' - pywarpx.warpx.moving_window_v = self.moving_window_velocity[1]/c # in units of the speed of light + pywarpx.warpx.moving_window_v = self.moving_window_velocity[1]/constants.c # in units of the speed of light if self.moving_window_velocity[2] != 0.: pywarpx.warpx.moving_window_dir = 'z' - pywarpx.warpx.moving_window_v = self.moving_window_velocity[2]/c # in units of the speed of light + pywarpx.warpx.moving_window_v = self.moving_window_velocity[2]/constants.c # in units of the speed of light if self.refined_regions: assert len(self.refined_regions) == 1, Exception('WarpX only supports one refined region.') @@ -415,7 +417,7 @@ class LaserAntenna(picmistandard.PICMI_LaserAntenna): laser.laser.position = self.position # This point is on the laser plane laser.laser.direction = self.normal_vector # The plane normal direction laser.laser.profile_focal_distance = laser.focal_position[2] - self.position[2] # Focal distance from the antenna (in meters) - laser.laser.profile_t_peak = (self.position[2] - laser.centroid_position[2])/c # The time at which the laser reaches its peak (in seconds) + laser.laser.profile_t_peak = (self.position[2] - laser.centroid_position[2])/constants.c # The time at which the laser reaches its peak (in seconds) class Simulation(picmistandard.PICMI_Simulation): -- cgit v1.2.3 From c49d9dbfb807ff84556c6cb0bf58c7368dd1d36a Mon Sep 17 00:00:00 2001 From: Dave Grote Date: Fri, 26 Jul 2019 17:46:04 -0700 Subject: In picmi, fixed Multispecies --- Python/pywarpx/picmi.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'Python/pywarpx/picmi.py') diff --git a/Python/pywarpx/picmi.py b/Python/pywarpx/picmi.py index fa72893d2..003ef523b 100644 --- a/Python/pywarpx/picmi.py +++ b/Python/pywarpx/picmi.py @@ -53,16 +53,18 @@ class Species(picmistandard.PICMI_Species): pywarpx.Particles.particles_list.append(self.species) if self.initial_distribution is not None: - self.initial_distribution.initialize_inputs(self.species_number, layout, self.species) + self.initial_distribution.initialize_inputs(self.species_number, layout, self.species, self.density_scale) picmistandard.PICMI_MultiSpecies.Species_class = Species class MultiSpecies(picmistandard.PICMI_MultiSpecies): - pass + def initialize_inputs(self, layout): + for species in self.species_instances_list: + species.initialize_inputs(layout) class GaussianBunchDistribution(picmistandard.PICMI_GaussianBunchDistribution): - def initialize_inputs(self, species_number, layout, species): + def initialize_inputs(self, species_number, layout, species, density_scale): species.injection_style = "gaussian_beam" species.x_m = self.centroid_position[0] species.y_m = self.centroid_position[1] @@ -81,6 +83,8 @@ class GaussianBunchDistribution(picmistandard.PICMI_GaussianBunchDistribution): elif charge == '-q_e': charge = -constants.q_e species.q_tot = self.n_physical_particles*charge + if density_scale is not None: + species.q_tot *= density_scale # --- These need to be defined even though they are not used species.profile = "constant" @@ -118,7 +122,7 @@ class GaussianBunchDistribution(picmistandard.PICMI_GaussianBunchDistribution): class UniformDistribution(picmistandard.PICMI_UniformDistribution): - def initialize_inputs(self, species_number, layout, species): + def initialize_inputs(self, species_number, layout, species, density_scale): if isinstance(layout, GriddedLayout): # --- Note that the grid attribute of GriddedLayout is ignored @@ -141,6 +145,8 @@ class UniformDistribution(picmistandard.PICMI_UniformDistribution): # --- Only constant density is supported at this time species.profile = "constant" species.density = self.density + if density_scale is not None: + species.density *= density_scale # --- Note that WarpX takes gamma*beta as input if np.any(np.not_equal(self.rms_velocity, 0.)): @@ -162,7 +168,7 @@ class UniformDistribution(picmistandard.PICMI_UniformDistribution): class AnalyticDistribution(picmistandard.PICMI_AnalyticDistribution): - def initialize_inputs(self, species_number, layout, species): + def initialize_inputs(self, species_number, layout, species, density_scale): if isinstance(layout, GriddedLayout): # --- Note that the grid attribute of GriddedLayout is ignored @@ -184,7 +190,10 @@ class AnalyticDistribution(picmistandard.PICMI_AnalyticDistribution): # --- Only constant density is supported at this time species.profile = "parse_density_function" - species.__setattr__('density_function(x,y,z)', self.density_expression) + if density_scale is None: + species.__setattr__('density_function(x,y,z)', self.density_expression) + else: + species.__setattr__('density_function(x,y,z)', "{}*({})".format(density_scale, self.density_expression)) for k,v in self.user_defined_kw.items(): setattr(pywarpx.my_constants, k, v) @@ -214,12 +223,14 @@ class ParticleListDistribution(picmistandard.PICMI_ParticleListDistribution): if len(x) > 1: raise Exception('Only a single particle can be loaded') - def initialize_inputs(self, species_number, layout, species): + def initialize_inputs(self, species_number, layout, species, density_scale): species.injection_style = "singleparticle" species.single_particle_pos = [self.x[0], self.y[0], self.z[0]] species.single_particle_vel = [self.ux[0]/constants.c, self.uy[0]/constants.c, self.uz[0]/constants.c] species.single_particle_weight = self.weight + if density_scale is not None: + species.single_particle_weight *= density_scale # --- These need to be defined even though they are not used species.profile = "constant" @@ -238,7 +249,7 @@ class GriddedLayout(picmistandard.PICMI_GriddedLayout): class PseudoRandomLayout(picmistandard.PICMI_PseudoRandomLayout): def init(self, kw): if self.seed is not None: - print('Warning: WarpX does not support specifying the random number seed') + print('Warning: WarpX does not support specifying the random number seed in PseudoRandomLayout') class BinomialSmoother(picmistandard.PICMI_BinomialSmoother): -- cgit v1.2.3 From 71a86503c92a872eb187bffd599e66cde06b22be Mon Sep 17 00:00:00 2001 From: Dave Grote Date: Fri, 26 Jul 2019 17:50:27 -0700 Subject: In picmi, add support for all elements --- Python/pywarpx/picmi.py | 25 ++++++++++++++++++++++--- Python/setup.py | 2 +- 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'Python/pywarpx/picmi.py') diff --git a/Python/pywarpx/picmi.py b/Python/pywarpx/picmi.py index 003ef523b..a0069ec8f 100644 --- a/Python/pywarpx/picmi.py +++ b/Python/pywarpx/picmi.py @@ -1,8 +1,10 @@ """Classes following the PICMI standard """ +import re import picmistandard import numpy as np import pywarpx +import periodictable codename = 'warpx' picmistandard.register_codename(codename) @@ -33,9 +35,26 @@ class Species(picmistandard.PICMI_Species): elif self.particle_type == 'anti-proton': if self.charge is None: self.charge = '-q_e' if self.mass is None: self.mass = 'm_p' - elif self.particle_type == 'H' and self.charge_state == 1: - if self.charge is None: self.charge = 'q_e' - if self.mass is None: self.mass = 'm_p' + else: + if self.charge is None and self.charge_state is not None: + self.charge = self.charge_state*constants.q_e + # Match a string of the format '#nXx', with the '#n' optional isotope number. + m = re.match('(?P#[\d+])*(?P[A-Za-z]+)', self.particle_type) + if m is not None: + element = periodictable.elements.symbol(m['sym']) + if m['iso'] is not None: + element = element[m['iso'][1:]] + if self.charge_state is not None: + assert self.charge_state <= element.number, Exception('%s charge state not valid'%self.particle_type) + try: + element = element.ion[self.charge_state] + except ValueError: + # Note that not all valid charge states are defined in elements, + # so this value error can be ignored. + pass + self.element = element + if self.mass is None: + self.mass = element.mass*periodictable.constants.atomic_mass_constant def initialize_inputs(self, layout): self.species_number = pywarpx.particles.nspecies diff --git a/Python/setup.py b/Python/setup.py index ecb87190c..8429cf95e 100644 --- a/Python/setup.py +++ b/Python/setup.py @@ -25,5 +25,5 @@ setup (name = 'pywarpx', package_dir = {'pywarpx':'pywarpx'}, description = """Wrapper of WarpX""", package_data = package_data, - install_requires=['picmistandard'] + install_requires=['picmistandard', 'periodictable'] ) -- cgit v1.2.3 From 16dba690f2e96173eaf477fb407933fe0ad00abe Mon Sep 17 00:00:00 2001 From: Dave Grote Date: Fri, 9 Aug 2019 09:47:49 -0700 Subject: Implemented picmi.BinomialSmoother --- Python/pywarpx/picmi.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Python/pywarpx/picmi.py') diff --git a/Python/pywarpx/picmi.py b/Python/pywarpx/picmi.py index a0069ec8f..35a29b850 100644 --- a/Python/pywarpx/picmi.py +++ b/Python/pywarpx/picmi.py @@ -272,7 +272,9 @@ class PseudoRandomLayout(picmistandard.PICMI_PseudoRandomLayout): class BinomialSmoother(picmistandard.PICMI_BinomialSmoother): - pass + def initialize_inputs(self): + pywarpx.warpx.use_filter = 1 + pywarpx.warpx.filter_npass_each_dir = self.n_pass class CylindricalGrid(picmistandard.PICMI_CylindricalGrid): @@ -418,6 +420,9 @@ class ElectromagneticSolver(picmistandard.PICMI_ElectromagneticSolver): if self.cfl is not None: pywarpx.warpx.cfl = self.cfl + if self.source_smoother is not None: + self.source_smoother.initialize_inputs() + class ElectrostaticSolver(picmistandard.PICMI_ElectrostaticSolver): def initialize_inputs(self): -- cgit v1.2.3 From 008eeedf79a615e4ae2d81dbd116eeb8e18be625 Mon Sep 17 00:00:00 2001 From: Dave Grote Date: Fri, 9 Aug 2019 11:32:08 -0700 Subject: Updates to picmi.BinomialSmoother --- Python/pywarpx/picmi.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'Python/pywarpx/picmi.py') diff --git a/Python/pywarpx/picmi.py b/Python/pywarpx/picmi.py index 35a29b850..47f8c562f 100644 --- a/Python/pywarpx/picmi.py +++ b/Python/pywarpx/picmi.py @@ -272,8 +272,17 @@ class PseudoRandomLayout(picmistandard.PICMI_PseudoRandomLayout): class BinomialSmoother(picmistandard.PICMI_BinomialSmoother): - def initialize_inputs(self): + def initialize_inputs(self, solver): pywarpx.warpx.use_filter = 1 + if self.n_pass is None: + # If not specified, do at least one pass in each direction. + self.n_pass = 1 + try: + # Check if n_pass is a vector + len(self.n_pass) + except TypeError: + # If not, make it a vector + self.n_pass = solver.grid.number_of_dimensions*[self.n_pass] pywarpx.warpx.filter_npass_each_dir = self.n_pass @@ -421,7 +430,7 @@ class ElectromagneticSolver(picmistandard.PICMI_ElectromagneticSolver): pywarpx.warpx.cfl = self.cfl if self.source_smoother is not None: - self.source_smoother.initialize_inputs() + self.source_smoother.initialize_inputs(self) class ElectrostaticSolver(picmistandard.PICMI_ElectrostaticSolver): -- cgit v1.2.3