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)
# Include the concept_dir in the searched paths import sys, os sys.path.append(os.environ['concept_dir']) # Imports from the CO𝘕CEPT code from commons import * from species import construct from snapshot import save # Create close to homogeneous particles N = 4**3 mass = Ωm*ϱ*boxsize**3/N mean_sep = boxsize/N**(1/3) max_mom = 0.5e+10*units.kpc/units.Gyr*units.m_sun particles = construct('dark matter particles', 'dark matter', mass, N) posx = zeros(N) posy = zeros(N) posz = zeros(N) momx = zeros(N) momy = zeros(N) momz = zeros(N) count = 0 for i in range(round(N**(1/3))): for j in range(round(N**(1/3))): for k in range(round(N**(1/3))): x = (i/N**(1/3)*boxsize + (random()*2 - 1)*mean_sep*0.1) % boxsize y = (j/N**(1/3)*boxsize + (random()*2 - 1)*mean_sep*0.1) % boxsize z = (k/N**(1/3)*boxsize + (random()*2 - 1)*mean_sep*0.1) % boxsize posx[count] = x posy[count] = y
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)
# This file has to be run in pure Python mode! # Include the concept_dir in the searched paths import sys, os sys.path.append(os.environ["concept_dir"]) # Imports from the CO𝘕CEPT code from commons import * from species import construct from snapshot import save # Create the particles. # It is important that no interparticle separation exceeds boxsize/2 in # any direction, as the nearest particle image in all cases must be the # actual particle itself. N = 8 mass = Ωm * ϱ * boxsize ** 3 / N particles = construct("dark matter particles", "dark matter", mass, N) particles.populate(array([0.26] * 4 + [0.74] * 4) * boxsize, "posx") particles.populate(array([0.25, 0.25, 0.75, 0.75] * 2) * boxsize, "posy") particles.populate(array([0.25, 0.75, 0.75, 0.25] * 2) * boxsize, "posz") particles.populate(zeros(N), "momx") particles.populate(zeros(N), "momy") particles.populate(zeros(N), "momz") # Save snapshot save(particles, a_begin, IC_file)