So, I'm foraying into the world of plasma simulation. Now, while I'm aware that top-level simulations are written in fortran and have ultra-memory efficient subroutines and specialized code, I'm hoping to just run some low-level simulations.
My problem is that, when simulating a large number of particles in a time-varying environment (well, time-stepped), keeping track of all that data is a trick. I've used multi-dimensional arrays before - using the column number for the particle, and the row number for the attribute, however this feels rather clumsy. It does, however, seem to be more quickly executed.
I recently tried defining my own class, however being a python newbie, I probably did it in a very inefficient way. For each particle in 3 dimensions, I needed to be able to store the particle's position, velocity and Force (with the potential to add more variables once the code becomes more complex). Using what I knew of classes, I defined a particle
object (I think) that make my code much easier to read and follow:
# Define Particle as a class
class particle():
def __init__(self, index=0, pos=np.array([0, 0, 0]), vel=np.array([0,0,0]),
F=np.array([0, 0, 0])):
self.index = index # Particle index (identifier)
self.pos = pos # Position 3-vector
self.vel = vel # Velocity 3-vector
self.F = F # Net force 3-vector (at particle)
So, I can easily initialize an array containing lots of these objects, and modify each value in a reasonably straightforward way. However as I mentioned, this ran slower for simulations involving only a few particles. I will be playing with my code to compare it to a purely matrix-oriented method to see which one scales better with large simulations.
My question I suppose then is this: Is defining a "particle" in this way the most efficient? Or is there a more CPU/memory efficient way to define such an object. I would like to keep it's method ability (i.e. particle[i].pos = [1,2,3]
or particle[2].vx[1] = 3
) so I can set values for each particle, as well as pass them through functions. Keep in mind I'm a Python newbie, so I probably won't have great success with large, complex code.
Python uses a garbage collection algorithm (called Garbage Collector) that keeps the Heap memory clean and removes objects that are not needed anymore. You don't need to mess with the Heap, but it is better to understand how Python manages the Heap since most of your data is stored in this section of the memory.
In general a class or struct is a concept and does not occupy variable (data) space, but it does take up memory in the compiler's memory.
Python has a built-in module named 'array' which is similar to arrays in C or C++. In this container, the data is stored in a contiguous block of memory. Just like arrays in C or C++, these arrays only support one data type at a time, therefore it's not heterogenous like Python lists. The indexing is similar to lists.
hex() is the memory hexadecimal representation to the address. id is used to get the memory of the object. object is the data.
__slots__
One way to save memory is using slots:
class Particle(): # Python 3
__slots__ = ['index', 'pos', 'vel', 'F']
def __init__(self, index=0, pos=None, vel=None, F=None):
# Particle index (identifier)
self.index = index
# Position 3-vector
self.pos = np.array([0, 0, 0]) if pos is None else pos
# Velocity 3-vector
self.vel = np.array([0,0,0]) if vel is None else vel
# Net force 3-vector (at particle)
self.F = np.array([0, 0, 0]) if F is None else F
From the docs:
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances.
__slots__
reserves space for the declared variables and prevents the automatic creation of__dict__
and__weakref__
for each instance.
Side note: I fixed the mutable default argument problem by setting them to None
and creating a new NumPy array in the __init__()
for None
values.
One important difference is that you cannot add attributes after instantiation that are not listed in __slots__
:
p = Particle()
p.new_attr = 45
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-664-a970d86f4ca3> in <module>()
1 p = Particle()
2
----> 3 p.new_attr = 45
AttributeError: 'Particle' object has no attribute 'new_attr'
Compare to a class without __slots__
:
class A: # Python 3
pass
a = A()
a.new_attr = 10
No exception is raised.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With