Beispiel #1
0
 def drift(self, Δt):
     """Note that the time step size
     Δt is really ∫_t^(t + Δt) dt/a**2.
     """
     masterprint('Drifting', self.type, '...')
     # Extracting variables
     posx = self.posx
     posy = self.posy
     posz = self.posz
     momx = self.momx
     momy = self.momy
     momz = self.momz
     # The factor 1/mass*∫_t^(t + Δt) dt/a**2
     fac = Δt/self.mass
     # Update positions
     for i in range(self.N_local):
         posx[i] += momx[i]*fac
         posy[i] += momy[i]*fac
         posz[i] += momz[i]*fac
         # Toroidal boundaries
         posx[i] = mod(posx[i], boxsize)
         posy[i] = mod(posy[i], boxsize)
         posz[i] = mod(posz[i], boxsize)
     # Some partiles may have drifted out of the local domain.
     # Exchange particles to the correct processes.
     masterprint('done')
     exchange(self)
Beispiel #2
0
 def load(self, filename, compare_params=True, only_params=False):
     # Load all particles
     with h5py.File(filename,
                    mode='r',
                    driver='mpio',
                    comm=comm,
                    ) as hdf5_file:
         # Load used base units
         snapshot_unit_length = eval(hdf5_file.attrs['unit length'], units_dict)
         snapshot_unit_time   = eval(hdf5_file.attrs['unit time'],   units_dict)
         snapshot_unit_mass   = eval(hdf5_file.attrs['unit mass'],   units_dict)
         # Load global attributes
         self.params['a']       = hdf5_file.attrs['a']
         self.params['boxsize'] = hdf5_file.attrs['boxsize']*snapshot_unit_length
         self.params['H0']      = hdf5_file.attrs['H0']*(1/snapshot_unit_time)
         self.params['Ωm']      = hdf5_file.attrs[unicode('Ω') + 'm']
         self.params['ΩΛ']      = hdf5_file.attrs[unicode('Ω') + unicode('Λ')]
         # Check if the parameters of the snapshot
         # matches those of the current simulation run.
         # Display a warning if they do not.
         if compare_params:
             tol = 1e-4
             msg = ''
             if np.abs(self.params['a']/a_begin - 1) > tol:
                 msg += ('\n' + ' '*8 + 'a_begin: {} vs {}'
                         ).format(a_begin, self.params['a'])
             if np.abs(self.params['boxsize']/boxsize - 1) > tol:
                 msg += ('\n' + ' '*8 + 'boxsize: {} vs {} ({})').format(boxsize,
                                                                         self.params['boxsize'],
                                                                         units.length)
             if np.abs(self.params['H0']/H0 - 1) > tol:
                 unit = units.km/(units.s*units.Mpc)
                 msg += ('\n' + ' '*8 + 'H0: {} vs {} ({})').format(H0/unit,
                                                                    self.params['H0']/unit,
                                                                    'km s⁻¹ Mpc⁻¹')
             if np.abs(self.params['Ωm']/Ωm - 1) > tol:
                 msg += ('\n' + ' '*8 + unicode('Ω') + 'm: {} vs {}').format(Ωm,
                                                                             self.params['Ωm'])
             if np.abs(self.params['ΩΛ']/ΩΛ - 1) > tol:
                 msg += ('\n' + ' '*8 + unicode('Ω')
                                      + unicode('Λ') + ': {} vs {}').format(ΩΛ,
                                                                            self.params['ΩΛ'])
             if msg:
                 msg = ('Mismatch between current parameters and those in'
                        + 'the snapshot "{}":{}').format(filename, msg)
                 masterwarn(msg, indent=4)
         # Initialize the particle_attributes dict
         self.params['particle_attributes'] = {}
         # Load particle data
         all_particles = hdf5_file['particles']
         for particle_type in all_particles:
             # Load particle attributes
             particles_h5 = all_particles[particle_type]
             particle_N = particles_h5['posx'].size
             particle_mass = particles_h5.attrs['mass']*snapshot_unit_mass
             particle_species = particles_h5.attrs['species']
             # The keys in the particle_attributes dict are the
             # particle types, and the values are new dicts,
             # containing the information for each type.
             self.params['particle_attributes'][particle_type] = {}
             particle_attribute = self.params['particle_attributes'][particle_type]
             particle_attribute['N']       = particle_N
             particle_attribute['mass']    = particle_mass
             particle_attribute['species'] = particle_species
             # Done loading particle attributes
             if only_params:
                 continue
             # Write out progress message
             masterprint('Loading', particle_N, particle_type,
                         '({}) ...'.format(particle_species),
                         indent=4)
             # Extract HDF5 datasets
             posx_h5 = particles_h5['posx']
             posy_h5 = particles_h5['posy']
             posz_h5 = particles_h5['posz']
             momx_h5 = particles_h5['momx']
             momy_h5 = particles_h5['momy']
             momz_h5 = particles_h5['momz']
             # Compute a fair distribution of 
             # particle data to the processes.
             N_locals = ((particle_N//nprocs, )
                         *(nprocs - (particle_N % nprocs))
                         + (particle_N//nprocs + 1, )*(particle_N % nprocs))
             N_local = N_locals[rank]
             start_local = np.sum(N_locals[:rank], dtype=C2np['Py_ssize_t'])
             end_local = start_local + N_local
             # Construct a Particles instance
             self.particles = construct(particle_type,
                                        particle_species,
                                        mass=particle_mass,
                                        N=particle_N)
             # Populate the Particles instance with data from the file
             self.particles.populate(posx_h5[start_local:end_local], 'posx')
             self.particles.populate(posy_h5[start_local:end_local], 'posy')
             self.particles.populate(posz_h5[start_local:end_local], 'posz')
             self.particles.populate(momx_h5[start_local:end_local], 'momx')
             self.particles.populate(momy_h5[start_local:end_local], 'momy')
             self.particles.populate(momz_h5[start_local:end_local], 'momz')
             # If the snapshot and the current run uses different
             # systems of units, mulitply the particle positions
             # and momenta by the snapshot units.
             if snapshot_unit_length != 1:
                 for i in range(N_local):
                     self.particles.posx[i] *= snapshot_unit_length
                     self.particles.posy[i] *= snapshot_unit_length
                     self.particles.posz[i] *= snapshot_unit_length
             unit = snapshot_unit_length/snapshot_unit_time*snapshot_unit_mass
             if unit != 1:
                 for i in range(N_local):
                     self.particles.momx[i] *= unit
                     self.particles.momy[i] *= unit
                     self.particles.momz[i] *= unit
             # Finalize progress message
             masterprint('done')
     # Update the "contains" string
     if only_params:
         self.contains = 'params'
     else:
         self.contains = 'params and particles'
     # Scatter particles to the correct domain-specific process.
     # Setting reset_indices_send == True ensures that buffers
     # will be reset afterwards, as this initial exchange is not
     # representable for those to come.
     if 'particles' in self.contains:
         exchange(self.particles, reset_buffers=True)
Beispiel #3
0
 def load(self, filename, compare_params=True, only_params=False):
     """ It is assumed that the snapshot on the disk is a GADGET
     snapshot of type 2 and that it uses single precision. The
     GadgetSnapshot instance stores the data (positions and
     velocities) in double precision. Only GADGET type 1 (halo)
     particles, corresponding to dark matter particles,
     are supported.
     """
     # Only type 1 (halo) particles are supported
     particle_species = 'dark matter'
     particle_type = 'GADGET halos'
     # Read in the snapshot
     offset = 0
     with open(filename, 'rb') as f:
         # Read the HEAD block into a params['header'] dict.
         # No unit conversion will be done.
         offset = self.new_block(f, offset)
         name = self.read(f, '4s').decode('utf8')  # "HEAD"
         size = self.read(f, 'i')  # 264
         offset = self.new_block(f, offset)
         self.params['header'] = collections.OrderedDict()
         header = self.params['header']
         header['Npart']         = self.read(f, '6I')
         header['Massarr']       = self.read(f, '6d')
         header['Time']          = self.read(f, 'd')
         header['Redshift']      = self.read(f, 'd')
         header['FlagSfr']       = self.read(f, 'i')
         header['FlagFeedback']  = self.read(f, 'i')
         header['Nall']          = self.read(f, '6i')
         header['FlagCooling']   = self.read(f, 'i')
         header['NumFiles']      = self.read(f, 'i')
         header['BoxSize']       = self.read(f, 'd')
         header['Omega0']        = self.read(f, 'd')
         header['OmegaLambda']   = self.read(f, 'd')
         header['HubbleParam']   = self.read(f, 'd')
         header['FlagAge']       = self.read(f, 'i')
         header['FlagMetals']    = self.read(f, 'i')
         header['NallHW']        = self.read(f, '6i')
         header['flag_entr_ics'] = self.read(f, 'i')
         # Also include some of the header fields as parameters
         # directly in the params dict.
         self.params['a']       = header['Time']
         unit = units.kpc/header['HubbleParam']
         self.params['boxsize'] = header['BoxSize']*unit
         unit = 100*units.km/(units.s*units.Mpc)
         self.params['H0']      = header['HubbleParam']*unit
         self.params['Ωm']      = header['Omega0']
         self.params['ΩΛ']      = header['OmegaLambda']
         # Check if the parameters of the snapshot matches
         # those of the current simulation run. Display a warning
         # if they do not.
         if compare_params:
             tol = 1e-4
             msg = ''
             if np.abs(self.params['a']/a_begin - 1) > tol:
                 msg += '\n' + ' '*8 + 'a_begin: {} vs {}'.format(a_begin, self.params['a'])
             if np.abs(self.params['boxsize']/boxsize - 1) > tol:
                 msg += ('\n' + ' '*8 + 'boxsize: {} vs {} ({})').format(boxsize,
                                                                         self.params['boxsize'],
                                                                         units.length)
             if np.abs(self.params['H0']/H0 - 1) > tol:
                 unit = units.km/(units.s*units.Mpc)
                 msg += ('\n' + ' '*8 + 'H0: {} vs {} ({})').format(H0/unit,
                                                                    self.params['H0']/unit,
                                                                    'km s⁻¹ Mpc⁻¹')
             if np.abs(self.params['Ωm']/Ωm - 1) > tol:
                 msg += ('\n' + ' '*8 + unicode('Ω') + 'm: {} vs {}').format(Ωm,
                                                                             self.params['Ωm'])
             if np.abs(self.params['ΩΛ']/ΩΛ - 1) > tol:
                 msg += ('\n' + ' '*8 + unicode('Ω')
                                      + unicode('Λ') + '{} vs {}').format(ΩΛ,
                                                                          self.params['ΩΛ'])
             if msg:
                 msg = ('Mismatch between current parameters and those in '
                        + 'the GADGET snapshot '
                        + '"{}":{}').format(filename, msg)
                 masterwarn(msg, indent=4)
         # Initialize the particle_attributes dict
         self.params['particle_attributes'] = {}
         # The keys in the particle_attributes dict are the
         # particle types, and the values are new dicts,
         # containing the information for each type.
         self.params['particle_attributes'][particle_type] = {}
         particle_attribute = (self.params['particle_attributes']
                                          [particle_type])
         N = header['Npart'][1]
         particle_attribute['N'] = N
         unit = 1e+10*units.m_sun/header['HubbleParam']
         mass = header['Massarr'][1]*unit
         particle_attribute['mass'] = mass
         particle_attribute['species'] = particle_species
         # Done loading particle attributes
         if only_params:
             self.contains = 'params'
             return
         # Write out progress message
         masterprint('Loading', N, particle_type, '({}) ...'.format(particle_species), indent=4)
         # Compute a fair distribution
         # of particle data to the processes.
         N_locals = ((N//nprocs, )*(nprocs - (N % nprocs))
                     + (N//nprocs + 1, )*(N % nprocs))
         N_local = N_locals[rank]
         start_local = np.sum(N_locals[:rank], dtype=C2np['Py_ssize_t'])
         # Construct a Particles instance
         self.particles = construct(particle_type, particle_species, mass=mass, N=N)
         # Read in the POS block. The positions are given in kpc/h.
         offset = self.new_block(f, offset)
         unit = units.kpc/header['HubbleParam']
         name = self.read(f, '4s').decode('utf8')  # "POS "
         size = self.read(f, 'i')
         offset = self.new_block(f, offset)
         f.seek(12*start_local, 1)  # 12 = sizeof(float)*Ndims
         file_position = f.tell()
         self.particles.populate(asarray(np.fromfile(f, dtype=C2np['float'], count=3*N_local)
                                         [0::3], dtype=C2np['double'])*unit,
                                 'posx')
         f.seek(file_position)
         self.particles.populate(asarray(np.fromfile(f, dtype=C2np['float'], count=3*N_local)
                                         [1::3], dtype=C2np['double'])*unit,
                                 'posy')
         f.seek(file_position)
         self.particles.populate(asarray(np.fromfile(f, dtype=C2np['float'], count=3*N_local)
                                         [2::3], dtype=C2np['double'])*unit,
                                 'posz')
         # Read in the VEL block. The velocities are peculiar
         # velocities u=a*dx/dt divided by sqrt(a), given in km/s.
         offset = self.new_block(f, offset)
         unit = units.km/units.s*mass*header['Time']**1.5
         name = self.read(f, '4s').decode('utf8')  # "VEL "
         size = self.read(f, 'i')
         offset = self.new_block(f, offset)
         f.seek(12*start_local, 1)  # 12 = sizeof(float)*Ndims
         file_position = f.tell()
         self.particles.populate(asarray(np.fromfile(f, dtype=C2np['float'], count=3*N_local)
                                         [0::3], dtype=C2np['double'])*unit,
                                 'momx')
         f.seek(file_position)
         self.particles.populate(asarray(np.fromfile(f, dtype=C2np['float'], count=3*N_local)
                                         [1::3], dtype=C2np['double'])*unit,
                                 'momy')
         f.seek(file_position)
         self.particles.populate(asarray(np.fromfile(f, dtype=C2np['float'], count=3*N_local)
                                         [2::3], dtype=C2np['double'])*unit,
                                 'momz')
         # Read in the ID block.
         # The ID's will be distributed among all processes.
         offset = self.new_block(f, offset)
         name = self.read(f, '4s').decode('utf8')  # "ID  "
         size = self.read(f, 'i')
         offset = self.new_block(f, offset)
         f.seek(4*start_local, 1)  # 4 = sizeof(unsigned int)
         file_position = f.tell()
         self.ID = np.fromfile(f, dtype=C2np['unsigned int'], count=N_local)
         # Finalize progress message
         masterprint('done')
         # Possible additional meta data ignored
     # Update the "contains" string
     self.contains = 'params and particles'
     # Scatter particles to the correct domain-specific process.
     # Setting reset_indices_send == True ensures that buffers
     # will be reset afterwards, as this initial exchange is not
     # representable for those to come.
     exchange(self.particles, reset_buffers=True)
Beispiel #4
0
ids, active, XY = IO.load_grid_of_particles(rank, time = 0, input = True)
if rank == 0:
    Nparticles = np.sum(active)

# start at initial time
t = t_0
IO.save_grid_of_particles(ids, active, XY, t, rank)
#plot.plot(rank, XY[:,active], t, dt)

# main loop
print('\nstart time = %s' % t)

# Communicating, to avoid bad load balancing at the beginning
print('This is rank %s, communicating before mainloop' % (rank))
ids, XY, active = communication.exchange(comm, mpi_size, rank, ids, XY[0,:], XY[1,:], active)

while t + dt <= t_max:
    # Take Ndt timesteps
        
    # only take active particles into transport function
    # non-active particles should be in the end of the arrays,
    # so if we want we can use the index as XY[:,:np.sum(active)] instead
    print('This is rank %s, transporting %s particles' % (rank, np.sum(active)))
    sys.stdout.flush()
    XY[:,active], t = transport.transport(XY[:,active], active, t, Ndt, dt)
    #plot.plot(rank, XY[:,active], t, dt, name = '_after_transport-before_comm_')
    #t += dt # this increment is returned from transport-funcion
    ############
    # Then communicate
    '''