Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

More memory efficient way to define many objects of the same type

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.

like image 743
Yoshi Avatar asked Jan 28 '16 21:01

Yoshi


People also ask

How objects are stored in memory in python?

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.

Does class take 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.

How arrays are stored in memory in python?

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.

What is memory location in python?

hex() is the memory hexadecimal representation to the address. id is used to get the memory of the object. object is the data.


1 Answers

Save memory with __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.

Cannot add new attributes to instance

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.

like image 162
Mike Müller Avatar answered Sep 28 '22 09:09

Mike Müller