Setting a format file

In pNbody, defining a new format correspond to adding new methods in the main class NbodyDefault. This means, writing a new class called Nbody_yourformat where yourformat is a string you choos giving the name of your new format. In practice, you need to create a file called:

$HOME/.pNbody/formats/yourformat.py

The latter file must describe a new class derived from the main class NbodyDefault.

Lets look at the first lines of the Nbody_default class, used when no format is specified. If you have used the:

pNbody_ pNbody_copy-defaultconfig

script, you will naturally find this file here:

$HOME/.pNbody/formats/default.py

The class is described with the following lines:

class Nbody_default(NbodyDefault):
  """
  This class is usefull to create an empty Nbody object
  """

The NbodyDefault.get_read_fcts() and NbodyDefault.get_write_fcts() methods

Then you need to redfined important methods. Fist, start with the NbodyDefault.get_read_fcts() and NbodyDefault.get_write_fcts() ones. The role of these methods is to return the methods responsible of the reading/writing of your format. Several routines can be used. By default, these two methods return an empty list. Secondly, you need of course to defined these methods.

In the Nbody_default class this is done with the following lines:

def get_read_fcts(self):
  """
  returns the functions needed to read a file.
  """
  return [self.read_particles]

def get_write_fcts(self):
  """
  returns the functions needed to write a file.
  """
  return [self.write_particles]

The methods self.read_particles and self.write_particles will be the core the the io. And you will obviously need to define it.

In Nbody_default class these methods does simply nothing and are defined as follows:

def read_particles(self,f):
  """
  Function that read particles.
  """
  pass

def write_particles(self,f):
  """
  Function that write particles.
  """
  pass

Note that the methods must have as an argument the pointer f corresponding to the already opend file. Opening the file is done automatically by pNbody and you do not need to do it.

A very simple example : an ascii format

You can easilly read and write ascii files containing the positions, velocities and mass of particles, defining the following methods:

def read_particles(self,f):
  """
  Function that read particles.
  """
  from pNbody import io
  x,y,z,vx,vy,vz,m=io.read_ascii(f,range(7))
  self.pos = transpose(array([x,y,z])).astype(float32)
  self.vel = transpose(array([vx,vy,vz])).astype(float32)
  self.mass = m.astype(float32)

def write_particles(self,f):
  """
  Function that write particles.
  """
  for i in range(self.nbody):
    line = "%g %g %g %g %g %g %g \n" %(self.pos[i][0],self.pos[i][1],self.pos[i][2],self.vel[i][0],self.vel[i][1],self.vel[i][2],self.mass[i])
    f.write(line)

Note that way of doing things works but is not recomanded from a performace point of view. Of course, in this form, the format will not allows parallel io. You will have to work a littre bit more to do it.

Let’s try to use this new format. We assume here that you are in the $HOME/pnbody_examples directory. First we convert a gadget binary file to an ascii file:

>>> from pNbody import *
>>> nb = Nbody('gadget.dat',ftype='gadget')
>>> nb = nb.set_ftype('ascii')
>>> nb.get_ftype()
>>> nb.get_ftype()
'Nbody_ascii'
>>> nb.get_format_file()
'/home/leo/.pNbody/formats/gadget.py'

The last lines are simply used to check that everything works fine Now simply rename and save the file:

>>> nb.rename('ascii.dat')
>>> nb.write()

Out of the python interpreter, you can check the content of the file:

$ head ascii.dat
-7.77545 6.07969 0.0733488 0 0 0 6.10352e-05
3.92681 11.4814 0.327888 0 0 0 6.10352e-05
-2.93326 -1.03464 0.221822 0 0 0 6.10352e-05
-3.81556 -0.322033 0.0146847 0 0 0 6.10352e-05
-1.3225 -6.34532 0.586419 0 0 0 6.10352e-05
0.0257911 0.576679 0.595826 0 0 0 6.10352e-05
-1.71236 1.22864 -0.61255 0 0 0 6.10352e-05
-2.6153 -0.21298 0.0526232 0 0 0 6.10352e-05
-2.1161 -2.47928 -0.193715 0 0 0 6.10352e-05
-4.33257 15.8307 0.0778809 0 0 0 6.10352e-05

Now, open it and display to check:

>>> from pNbody import *
>>> nb = Nbody('ascii.dat',ftype='ascii')
>>> nb.display(size=(30,30))

And you should see an edge-on disk.

Some info on our ascii object

When creating an object, it is possible to check the the file that defines it format, using:

To list the content of the variables of an object:

>>> nb.get_list_of_vars()
['Density', 'DesNumNgb', 'Hsml', 'MaxNumNgbDeviation', 'Tree',
'__doc__', '__module__', '_formatfile', 'byteorder', 'defaultparameters',
'ftype', 'localsystem_of_units', 'log', 'mass_tot', 'nbody', 'nbody_tot',
'npart', 'npart_tot', 'p_name', 'p_name_global', 'parameters', 'pio',
'spec_vars', 'spec_vect', 'status', 'unitsfile', 'unitsparameters']

>>> nb.get_list_of_array()
['mass', 'num', 'pos', 'tpe', 'vel']

>>> nb.get_list_of_method()
['A', 'Accel', 'CombiHisto'
...
'zmodes', 'zprof']

>>> nb.get_default_spec_vars()
{}

>>> nb.get_default_spec_array()
{}

‘Density’, ‘DesNumNgb’, ‘Hsml’, ‘MaxNumNgbDeviation’, ‘Tree’

Other important methods

def get_default_spec_vars(self):

“”” Specific variables to this format “”” return {}

def get_default_spec_array(self):

“”” return specific array default values for the class “”” return {}

Thanks to the magic of the Python interpreted language, creating a new class derived from the main class NbodyDefault presents the excellent advantage of letting the opportunity to the user to add new methods (not related to the reading of writing of the format), dedicated to its new and private format, without modifying the pNbody source.

It is possible to list all know formats:

>>> from pNbody import main
>>> main.get_known_formats()
>>> main.get_known_formats()
['Nbody_binary', 'Nbody_bnbf', 'Nbody_default', 'Nbody_gadget', 'Nbody_simpleformat', 'Nbody_tipsy', 'Nbody_tipsybig']

The most simple pNbody object is created with the:

>>> from pNbody import *
>>> nb = Nbody()

To check the format:

>>> nb.ftype
'Nbody_default'

To give the directory where format files are read:

>>> FORMATSDIR
'/home/leo/.pNbody/formats'

To get the format file used:

>>> from pNbody import *
>>> nb = Nbody()
>>> nb.get_format_file()
'/home/leo/.pNbody/formats/default.py'

To list the