aboutsummaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/pywarpx/Bucket.py7
-rw-r--r--Python/pywarpx/PICMI.py160
-rw-r--r--Python/pywarpx/Particles.py2
-rw-r--r--Python/pywarpx/WarpX.py50
-rw-r--r--Python/pywarpx/__init__.py3
-rw-r--r--Python/pywarpx/timestepper.py2
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):