diff options
Diffstat (limited to 'Python/pywarpx')
-rw-r--r-- | Python/pywarpx/Bucket.py | 7 | ||||
-rw-r--r-- | Python/pywarpx/PICMI.py | 160 | ||||
-rw-r--r-- | Python/pywarpx/Particles.py | 2 | ||||
-rw-r--r-- | Python/pywarpx/WarpX.py | 50 | ||||
-rw-r--r-- | Python/pywarpx/__init__.py | 3 | ||||
-rw-r--r-- | Python/pywarpx/timestepper.py | 2 |
6 files changed, 197 insertions, 27 deletions
diff --git a/Python/pywarpx/Bucket.py b/Python/pywarpx/Bucket.py index 5c429f530..960fe2108 100644 --- a/Python/pywarpx/Bucket.py +++ b/Python/pywarpx/Bucket.py @@ -28,7 +28,12 @@ class Bucket(object): for attr, value in iteritems(self.argvattrs): # --- repr is applied to value so that for floats, all of the digits are included. # --- The strip is then needed when value is a string. - attrstring = '{0}.{1}={2} '.format(self.instancename, attr, repr(value).strip("'\"")) + if hasattr(value, '__iter__'): + # --- For lists, tuples, and arrays make a space delimited string of the values + rhs = ' '.join(map(repr, value)) + else: + rhs = value + attrstring = '{0}.{1}={2}'.format(self.instancename, attr, repr(rhs).strip("'\"")) result += [attrstring] return result diff --git a/Python/pywarpx/PICMI.py b/Python/pywarpx/PICMI.py index 1bc36e5ca..b1711926f 100644 --- a/Python/pywarpx/PICMI.py +++ b/Python/pywarpx/PICMI.py @@ -6,14 +6,10 @@ from pywarpx import * codename = 'WarpX' -def _args_to_string(*args): - # --- Converts of sequence of number to a string that is appropriate for input. - return ' '.join(map(repr, args)) - class Grid(PICMI_Grid): def init(self, **kw): - amr.n_cell = _args_to_string(self.nx, self.ny, self.nz) + amr.n_cell = [self.nx, self.ny, self.nz] # Maximum allowable size of each subdomain in the problem domain; # this is used to decompose the domain for parallel calculations. @@ -25,8 +21,8 @@ class Grid(PICMI_Grid): # Geometry geometry.coord_sys = kw.get('coord_sys', 0) # 0: Cartesian geometry.is_periodic = '%d %d %d'%(self.bcxmin=='periodic', self.bcymin=='periodic', self.bczmin=='periodic') # Is periodic? - geometry.prob_lo = _args_to_string(self.xmin, self.ymin, self.zmin) # physical domain - geometry.prob_hi = _args_to_string(self.xmax, self.ymax, self.zmax) + geometry.prob_lo = [self.xmin, self.ymin, self.zmin] # physical domain + geometry.prob_hi = [self.xmax, self.ymax, self.zmax] if self.moving_window_velocity is not None and np.any(self.moving_window_velocity != 0): warpx.do_moving_window = 1 @@ -78,15 +74,20 @@ class Gaussian_laser(PICMI_Gaussian_laser): warpx.use_laser = 1 laser.profile = "Gaussian" - laser.position = _args_to_string(self.antenna_x0, self.antenna_y0, self.antenna_z0) # This point is on the laser plane - laser.direction = _args_to_string(self.antenna_xvec, self.antenna_yvec, self.antenna_zvec) # The plane normal direction - laser.polarization = _args_to_string(np.cos(self.pol_angle), np.sin(self.pol_angle), 0.) # The main polarization vector + laser.wavelength = self.wavelength # The wavelength of the laser (in meters) laser.e_max = self.E0 # Maximum amplitude of the laser field (in V/m) + laser.polarization = [np.cos(self.pol_angle), np.sin(self.pol_angle), 0.] # The main polarization vector laser.profile_waist = self.waist # The waist of the laser (in meters) laser.profile_duration = self.duration # The duration of the laser (in seconds) - laser.profile_t_peak = self.t_peak # The time at which the laser reaches its peak (in seconds) - laser.profile_focal_distance = self.focal_position - self.antenna_z0 # Focal distance from the antenna (in meters) - laser.wavelength = self.wavelength # The wavelength of the laser (in meters) + laser.profile_t_peak = (self.focal_position - self.z0)/clight # The time at which the laser reaches its peak (in seconds) + + +class Laser_antenna(PICMI_Laser_antenna): + def init(self, **kw): + + laser.position = [self.antenna_x0, self.antenna_y0, self.antenna_z0] # This point is on the laser plane + laser.direction = [self.antenna_xvec, self.antenna_yvec, self.antenna_zvec] # The plane normal direction + laser.profile_focal_distance = self.laser.focal_position - self.antenna_z0 # Focal distance from the antenna (in meters) class Species(PICMI_Species): @@ -94,7 +95,10 @@ class Species(PICMI_Species): self.species_number = particles.nspecies particles.nspecies = particles.nspecies + 1 - particles.species_names = particles.species_names + ' ' + self.name + if particles.species_names is None: + particles.species_names = self.name + else: + particles.species_names = particles.species_names + ' ' + self.name self.bucket = Bucket.Bucket(self.name, mass=self.mass, charge=self.charge, injection_style = 'python') Particles.particles_list.append(self.bucket) @@ -107,6 +111,102 @@ class Species(PICMI_Species): add_particles(self.species_number, x, y, z, ux, uy, uz, pid, unique_particles) +class GaussianBeam(PICMI_GaussianBeam): + def init(self, **kw): + + self.species.bucket.injection_style = "gaussian_beam" + self.species.bucket.x_m = self.Xmean + self.species.bucket.y_m = self.Ymean + self.species.bucket.z_m = self.Zmean + self.species.bucket.x_rms = self.Xrms + self.species.bucket.y_rms = self.Yrms + self.species.bucket.z_rms = self.Zrms + self.species.bucket.npart = self.number_sim_particles + self.species.bucket.q_tot = self.number_sim_particles*self.species.charge + + # --- These are unused but need to be set (maybe) + self.species.bucket.profile = 'constant' + self.species.bucket.density = 1 + + # --- Momentum distribution + if 'u_over_r' in kw: + # --- Radial expansion + self.species.bucket.momentum_distribution_type = "radial_expansion" + self.species.bucket.u_over_r = kw['u_over_r'] + + elif self.UXrms == 0. and self.UYrms == 0. and self.UZrms == 0.: + # --- Constant velocity + self.species.bucket.momentum_distribution_type = "constant" + self.species.bucket.ux = self.UXmean + self.species.bucket.uy = self.UYmean + self.species.bucket.uz = self.UZmean + + else: + # --- Gaussian velocity distribution + self.species.bucket.momentum_distribution_type = "gaussian" + self.species.bucket.ux_m = self.UXmean + self.species.bucket.uy_m = self.UYmean + self.species.bucket.uz_m = self.UZmean + self.species.bucket.u_th = self.UZrms + # !!! UXrms and UYrms are unused. Only an isotropic distribution is supported + # !!! Maybe an error should be raised + + +class Plasma(PICMI_Plasma): + def init(self, **kw): + + for species in self.species: + species.bucket.injection_style = "NUniformPerCell" + species.bucket.xmin = self.xmin + species.bucket.xmax = self.xmax + species.bucket.ymin = self.ymin + species.bucket.ymax = self.ymax + species.bucket.zmin = self.zmin + species.bucket.zmax = self.zmax + + species.bucket.profile = 'constant' + species.bucket.density = self.density + + if self.number_per_cell is not None: + species.bucket.nrandompercell = self.number_per_cell + elif self.number_per_cell_each_dim is not None: + species.bucket.num_particles_per_cell_each_dim = self.number_per_cell_each_dim + + # --- Momentum distribution + if 'u_over_r' in kw: + # --- Radial expansion + species.bucket.momentum_distribution_type = "radial_expansion" + species.bucket.u_over_r = kw['u_over_r'] + + elif self.vthx == 0. and self.vthy == 0. and self.vthz == 0.: + # --- Constant velocity + species.bucket.momentum_distribution_type = "constant" + species.bucket.ux = self.vxmean + species.bucket.uy = self.vymean + species.bucket.uz = self.vzmean + + else: + # --- Gaussian velocity distribution + species.bucket.momentum_distribution_type = "gaussian" + species.bucket.ux_m = self.vxmean + species.bucket.uy_m = self.vymean + species.bucket.uz_m = self.vzmean + species.bucket.u_th = self.vthz + # !!! vthx and vthy are unused. Only an isotropic distribution is supported + # !!! Maybe an error should be raised + + +class ParticleList(PICMI_ParticleList): + def init(self, **kw): + + assert len(self.x) == 1, "WarpX only supports initializing with a single particle" + + self.species.bucket.injection_style = "SingleParticle" + self.species.bucket.single_particle_pos = [self.x[0], self.y[0], self.z[0]] + self.species.bucket.single_particle_vel = [self.ux[0]/clight, self.uy[0]/clight, self.uz[0]/clight] + self.species.bucket.single_particle_weight = self.weight + + class Simulation(PICMI_Simulation): def set_warpx_attr(self, warpx_obj, attr, kw): value = kw.get(attr, None) @@ -117,17 +217,35 @@ class Simulation(PICMI_Simulation): def init(self, **kw): warpx.verbose = self.verbose - warpx.cfl = self.cfl + warpx.cfl = self.timestep_over_cfl + if self.timestep == 0.: + warpx.cfl = self.timestep_over_cfl + else: + warpx.const_dt = self.timestep amr.plot_int = self.plot_int - self.amrex = AMReX() - self.amrex.init() - warpx.init() - - def step(self, nsteps=-1): + self.initialized = False + + def initialize(self, inputs_name=None): + if not self.initialized: + self.initialized = True + warpx.init() + + def write_inputs(self, inputs_name='inputs'): + kw = {} + if hasattr(self, 'max_step'): + kw['max_step'] = self.max_step + warpx.write_inputs(inputs_name, **kw) + + def step(self, nsteps=None): + self.initialize() + if nsteps is None: + if self.max_step is not None: + nsteps = self.max_step + else: + nsteps = -1 warpx.evolve(nsteps) def finalize(self): warpx.finalize() - self.amrex.finalize() diff --git a/Python/pywarpx/Particles.py b/Python/pywarpx/Particles.py index e7bac7e10..395a888d7 100644 --- a/Python/pywarpx/Particles.py +++ b/Python/pywarpx/Particles.py @@ -1,6 +1,6 @@ from .Bucket import Bucket -particles = Bucket('particles', nspecies=0, species_names='') +particles = Bucket('particles', nspecies=0, species_names=None) particles_list = [] electrons = Bucket('electrons') diff --git a/Python/pywarpx/WarpX.py b/Python/pywarpx/WarpX.py index f0a31f3f9..7a05c40fb 100644 --- a/Python/pywarpx/WarpX.py +++ b/Python/pywarpx/WarpX.py @@ -1,19 +1,56 @@ from .Bucket import Bucket + +from .Amr import amr +from .Geometry import geometry +from .Algo import algo +from .Langmuirwave import langmuirwave +from .Interpolation import interpolation +from .Laser import laser +from . import Particles +from .Particles import particles, particles_list + +import ctypes from ._libwarpx import libwarpx +from ._libwarpx import amrex_init class WarpX(Bucket): """ A Python wrapper for the WarpX C++ class """ + def create_argv_list(self): + argv = [] + argv += warpx.attrlist() + argv += amr.attrlist() + argv += geometry.attrlist() + argv += algo.attrlist() + argv += langmuirwave.attrlist() + argv += interpolation.attrlist() + argv += particles.attrlist() + argv += laser.attrlist() + + if not particles_list: + # --- This is needed in case only species_names has been set, + # --- assuming that only the built in particle types are being used. + for pstring in particles.species_names.split(' '): + particles_list.append(getattr(Particles, pstring)) + + for particle in particles_list: + argv += particle.attrlist() + + return argv + def init(self): + argv = ['warpx'] + self.create_argv_list() + amrex_init(argv) libwarpx.warpx_init() def evolve(self, nsteps=-1): libwarpx.warpx_evolve(nsteps) - def finalize(self): + def finalize(self, finalize_mpi=1): libwarpx.warpx_finalize() + libwarpx.amrex_finalize(finalize_mpi) def getProbLo(self, direction): return libwarpx.warpx_getProbLo(direction) @@ -21,4 +58,15 @@ class WarpX(Bucket): def getProbHi(self, direction): return libwarpx.warpx_getProbHi(direction) + def write_inputs(self, filename='inputs', **kw): + argv = self.create_argv_list() + with open(filename, 'w') as ff: + + for k, v in kw.iteritems(): + ff.write('{0} = {1}\n'.format(k, v)) + + for arg in argv: + ff.write('{0}\n'.format(arg)) + warpx = WarpX('warpx') + diff --git a/Python/pywarpx/__init__.py b/Python/pywarpx/__init__.py index a4c83deab..cd6237d39 100644 --- a/Python/pywarpx/__init__.py +++ b/Python/pywarpx/__init__.py @@ -5,9 +5,8 @@ from .Geometry import geometry from .Algo import algo from .Langmuirwave import langmuirwave from .Interpolation import interpolation -from .Particles import particles +from .Particles import particles, electrons, positrons, protons from .Laser import laser -from .AMReX import AMReX #from .timestepper import TimeStepper from .PGroup import PGroup diff --git a/Python/pywarpx/timestepper.py b/Python/pywarpx/timestepper.py index fe58c623f..3068cbc82 100644 --- a/Python/pywarpx/timestepper.py +++ b/Python/pywarpx/timestepper.py @@ -1,5 +1,5 @@ from ._libwarpx import libwarpx -import .callbacks +from . import callbacks class TimeStepper(object): |