def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer( self.ds.domain_dimensions / 2, self.ds.domain_left_edge, self.ds.domain_right_edge, ) root_nodes = self.amr_header["numbl"][self.ds.min_level, :].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) mylog.debug( "Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum(), ) f = self.amr_file f.seek(self.amr_offset) min_level = self.ds.min_level max_level = read_amr( f, self.amr_header, self.ngridbound, min_level, self.oct_handler ) self.max_level = max_level self.oct_handler.finalize() # Close AMR file f.close()
class RAMSESDomainFile: _last_mask = None _last_selector_id = None def __init__(self, ds, domain_id): self.ds = ds self.domain_id = domain_id num = os.path.basename(ds.parameter_filename).split(".")[0].split("_")[1] rootdir = ds.root_folder basedir = os.path.abspath(os.path.dirname(ds.parameter_filename)) basename = "%s/%%s_%s.out%05i" % (basedir, num, domain_id) part_file_descriptor = f"{basedir}/part_file_descriptor.txt" if ds.num_groups > 0: igroup = ((domain_id - 1) // ds.group_size) + 1 basename = "%s/group_%05i/%%s_%s.out%05i" % ( rootdir, igroup, num, domain_id, ) else: basename = "%s/%%s_%s.out%05i" % (basedir, num, domain_id) for t in ["grav", "amr"]: setattr(self, f"{t}_fn", basename % t) self._part_file_descriptor = part_file_descriptor self._read_amr_header() # Autodetect field files field_handlers = [FH(self) for FH in get_field_handlers() if FH.any_exist(ds)] self.field_handlers = field_handlers for fh in field_handlers: mylog.debug("Detected fluid type %s in domain_id=%s", fh.ftype, domain_id) fh.detect_fields(ds) # self._add_ftype(fh.ftype) # Autodetect particle files particle_handlers = [ PH(self) for PH in get_particle_handlers() if PH.any_exist(ds) ] self.particle_handlers = particle_handlers for ph in particle_handlers: mylog.debug( "Detected particle type %s in domain_id=%s", ph.ptype, domain_id ) ph.read_header() # self._add_ptype(ph.ptype) # Load the AMR structure self._read_amr() _hydro_offset = None _level_count = None def __repr__(self): return "RAMSESDomainFile: %i" % self.domain_id @property def level_count(self): lvl_count = None for fh in self.field_handlers: fh.offset if lvl_count is None: lvl_count = fh.level_count.copy() else: lvl_count += fh._level_count return lvl_count @property def amr_file(self): if hasattr(self, "_amr_file"): self._amr_file.seek(0) return self._amr_file f = fpu(self.amr_fn) self._amr_file = f f.seek(0) return f def _read_amr_header(self): hvals = {} f = self.amr_file f.seek(0) for header in ramses_header(hvals): hvals.update(f.read_attrs(header)) # For speedup, skip reading of 'headl' and 'taill' f.skip(2) hvals["numbl"] = f.read_vector("i") # That's the header, now we skip a few. hvals["numbl"] = np.array(hvals["numbl"]).reshape( (hvals["nlevelmax"], hvals["ncpu"]) ) f.skip() if hvals["nboundary"] > 0: f.skip(2) self.ngridbound = f.read_vector("i").astype("int64") else: self.ngridbound = np.zeros(hvals["nlevelmax"], dtype="int64") free_mem = f.read_attrs((("free_mem", 5, "i"),)) # NOQA ordering = f.read_vector("c") # NOQA f.skip(4) # Now we're at the tree itself # Now we iterate over each level and each CPU. self.amr_header = hvals # update levelmax force_max_level, convention = self.ds._force_max_level if convention == "yt": force_max_level += self.ds.min_level + 1 self.amr_header["nlevelmax"] = min( force_max_level, self.amr_header["nlevelmax"] ) self.amr_offset = f.tell() self.local_oct_count = hvals["numbl"][ self.ds.min_level :, self.domain_id - 1 ].sum() self.total_oct_count = hvals["numbl"][self.ds.min_level :, :].sum(axis=0) def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer( self.ds.domain_dimensions / 2, self.ds.domain_left_edge, self.ds.domain_right_edge, ) root_nodes = self.amr_header["numbl"][self.ds.min_level, :].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) mylog.debug( "Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum(), ) f = self.amr_file f.seek(self.amr_offset) min_level = self.ds.min_level max_level = read_amr( f, self.amr_header, self.ngridbound, min_level, self.oct_handler ) self.max_level = max_level self.oct_handler.finalize() # Close AMR file f.close() def included(self, selector): if getattr(selector, "domain_id", None) is not None: return selector.domain_id == self.domain_id domain_ids = self.oct_handler.domain_identify(selector) return self.domain_id in domain_ids
def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer(self.ds.domain_dimensions / 2, self.ds.domain_left_edge, self.ds.domain_right_edge) root_nodes = self.amr_header['numbl'][self.ds.min_level, :].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) mylog.debug("Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum()) f = self.amr_file f.seek(self.amr_offset) def _ng(c, l): if c < self.amr_header['ncpu']: ng = self.amr_header['numbl'][l, c] else: ng = self.ngridbound[c - self.amr_header['ncpu'] + self.amr_header['nboundary'] * l] return ng min_level = self.ds.min_level # yt max level is not the same as the RAMSES one. # yt max level is the maximum number of additional refinement levels # so for a uni grid run with no refinement, it would be 0. # So we initially assume that. max_level = 0 nx, ny, nz = (((i - 1.0) / 2.0) for i in self.amr_header['nx']) for level in range(self.amr_header['nlevelmax']): # Easier if do this 1-indexed for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): #ng is the number of octs on this level on this domain ng = _ng(cpu, level) if ng == 0: continue ind = fpu.read_vector(f, "I").astype("int64") # NOQA fpu.skip(f, 2) pos = np.empty((ng, 3), dtype='float64') pos[:, 0] = fpu.read_vector(f, "d") - nx pos[:, 1] = fpu.read_vector(f, "d") - ny pos[:, 2] = fpu.read_vector(f, "d") - nz #pos *= self.ds.domain_width #pos += self.dataset.domain_left_edge fpu.skip(f, 31) #parents = fpu.read_vector(f, "I") #fpu.skip(f, 6) #children = np.empty((ng, 8), dtype='int64') #for i in range(8): # children[:,i] = fpu.read_vector(f, "I") #cpu_map = np.empty((ng, 8), dtype="int64") #for i in range(8): # cpu_map[:,i] = fpu.read_vector(f, "I") #rmap = np.empty((ng, 8), dtype="int64") #for i in range(8): # rmap[:,i] = fpu.read_vector(f, "I") # We don't want duplicate grids. # Note that we're adding *grids*, not individual cells. if level >= min_level: assert (pos.shape[0] == ng) n = self.oct_handler.add(cpu + 1, level - min_level, pos, count_boundary=1) self._error_check(cpu, level, pos, n, ng, (nx, ny, nz)) if n > 0: max_level = max(level - min_level, max_level) self.max_level = max_level self.oct_handler.finalize() # Close AMR file f.close()
class RAMSESDomainFile(object): _last_mask = None _last_selector_id = None def __init__(self, ds, domain_id): self.ds = ds self.domain_id = domain_id num = os.path.basename( ds.parameter_filename).split(".")[0].split("_")[1] basedir = os.path.abspath(os.path.dirname(ds.parameter_filename)) basename = "%s/%%s_%s.out%05i" % (basedir, num, domain_id) part_file_descriptor = "%s/part_file_descriptor.txt" % basedir for t in ['grav', 'amr']: setattr(self, "%s_fn" % t, basename % t) self._part_file_descriptor = part_file_descriptor self._read_amr_header() # self._read_hydro_header() # Autodetect field files field_handlers = [ FH(self) for FH in get_field_handlers() if FH.any_exist(ds) ] self.field_handlers = field_handlers for fh in field_handlers: mylog.debug('Detected fluid type %s in domain_id=%s' % (fh.ftype, domain_id)) fh.detect_fields(ds) # self._add_ftype(fh.ftype) # Autodetect particle files particle_handlers = [ PH(ds, domain_id) for PH in get_particle_handlers() if PH.any_exist(ds) ] self.particle_handlers = particle_handlers for ph in particle_handlers: mylog.debug('Detected particle type %s in domain_id=%s' % (ph.ptype, domain_id)) ph.read_header() # self._add_ptype(ph.ptype) # Load the AMR structure self._read_amr() _hydro_offset = None _level_count = None def __repr__(self): return "RAMSESDomainFile: %i" % self.domain_id @property def level_count(self): lvl_count = None for fh in self.field_handlers: fh.offset if lvl_count is None: lvl_count = fh.level_count.copy() else: lvl_count += fh._level_count return lvl_count @property def amr_file(self): if hasattr(self, '_amr_file'): self._amr_file.seek(0) return self._amr_file f = open(self.amr_fn, "rb") self._amr_file = f f.seek(0) return f def _read_amr_header(self): hvals = {} f = self.amr_file f.seek(0) for header in ramses_header(hvals): hvals.update(fpu.read_attrs(f, header)) # For speedup, skip reading of 'headl' and 'taill' fpu.skip(f, 2) hvals['numbl'] = fpu.read_vector(f, 'i') # That's the header, now we skip a few. hvals['numbl'] = np.array(hvals['numbl']).reshape( (hvals['nlevelmax'], hvals['ncpu'])) fpu.skip(f) if hvals['nboundary'] > 0: fpu.skip(f, 2) self.ngridbound = fpu.read_vector(f, 'i').astype("int64") else: self.ngridbound = np.zeros(hvals['nlevelmax'], dtype='int64') free_mem = fpu.read_attrs(f, (('free_mem', 5, 'i'), )) # NOQA ordering = fpu.read_vector(f, 'c') # NOQA fpu.skip(f, 4) # Now we're at the tree itself # Now we iterate over each level and each CPU. self.amr_header = hvals self.amr_offset = f.tell() self.local_oct_count = hvals['numbl'][self.ds.min_level:, self.domain_id - 1].sum() self.total_oct_count = hvals['numbl'][self.ds.min_level:, :].sum( axis=0) def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer(self.ds.domain_dimensions / 2, self.ds.domain_left_edge, self.ds.domain_right_edge) root_nodes = self.amr_header['numbl'][self.ds.min_level, :].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) mylog.debug("Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum()) f = self.amr_file f.seek(self.amr_offset) def _ng(c, l): if c < self.amr_header['ncpu']: ng = self.amr_header['numbl'][l, c] else: ng = self.ngridbound[c - self.amr_header['ncpu'] + self.amr_header['nboundary'] * l] return ng min_level = self.ds.min_level # yt max level is not the same as the RAMSES one. # yt max level is the maximum number of additional refinement levels # so for a uni grid run with no refinement, it would be 0. # So we initially assume that. max_level = 0 nx, ny, nz = (((i - 1.0) / 2.0) for i in self.amr_header['nx']) for level in range(self.amr_header['nlevelmax']): # Easier if do this 1-indexed for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): #ng is the number of octs on this level on this domain ng = _ng(cpu, level) if ng == 0: continue ind = fpu.read_vector(f, "I").astype("int64") # NOQA fpu.skip(f, 2) pos = np.empty((ng, 3), dtype='float64') pos[:, 0] = fpu.read_vector(f, "d") - nx pos[:, 1] = fpu.read_vector(f, "d") - ny pos[:, 2] = fpu.read_vector(f, "d") - nz #pos *= self.ds.domain_width #pos += self.dataset.domain_left_edge fpu.skip(f, 31) #parents = fpu.read_vector(f, "I") #fpu.skip(f, 6) #children = np.empty((ng, 8), dtype='int64') #for i in range(8): # children[:,i] = fpu.read_vector(f, "I") #cpu_map = np.empty((ng, 8), dtype="int64") #for i in range(8): # cpu_map[:,i] = fpu.read_vector(f, "I") #rmap = np.empty((ng, 8), dtype="int64") #for i in range(8): # rmap[:,i] = fpu.read_vector(f, "I") # We don't want duplicate grids. # Note that we're adding *grids*, not individual cells. if level >= min_level: assert (pos.shape[0] == ng) n = self.oct_handler.add(cpu + 1, level - min_level, pos, count_boundary=1) self._error_check(cpu, level, pos, n, ng, (nx, ny, nz)) if n > 0: max_level = max(level - min_level, max_level) self.max_level = max_level self.oct_handler.finalize() # Close AMR file f.close() def _error_check(self, cpu, level, pos, n, ng, nn): # NOTE: We have the second conditional here because internally, it will # not add any octs in that case. if n == ng or cpu + 1 > self.oct_handler.num_domains: return # This is where we now check for issues with creating the new octs, and # we attempt to determine what precisely is going wrong. # These are all print statements. print("We have detected an error with the construction of the Octree.") print(" The number of Octs to be added : %s" % ng) print(" The number of Octs added : %s" % n) print(" Level : %s" % level) print(" CPU Number (0-indexed) : %s" % cpu) for i, ax in enumerate('xyz'): print(" extent [%s] : %s %s" % \ (ax, pos[:,i].min(), pos[:,i].max())) print(" domain left : %s" % \ (self.ds.domain_left_edge,)) print(" domain right : %s" % \ (self.ds.domain_right_edge,)) print(" offset applied : %s %s %s" % \ (nn[0], nn[1], nn[2])) print("AMR Header:") for key in sorted(self.amr_header): print(" %-30s: %s" % (key, self.amr_header[key])) raise RuntimeError def included(self, selector): if getattr(selector, "domain_id", None) is not None: return selector.domain_id == self.domain_id domain_ids = self.oct_handler.domain_identify(selector) return self.domain_id in domain_ids
from yt.geometry.fake_octree import create_fake_octree from yt.geometry.oct_container import RAMSESOctreeContainer, ParticleOctreeContainer import numpy as np nocts = 3 max_level = 12 dn = 2 dd = np.ones(3, dtype='i4') * dn dle = np.ones(3, dtype='f8') * 0.0 dre = np.ones(3, dtype='f8') fsub = 0.25 domain = 1 oct_handler = RAMSESOctreeContainer(dd, dle, dre) leaves = create_fake_octree(oct_handler, nocts, max_level, dd, dle, dre, fsub) mask = np.ones((nocts, 8), dtype='bool') cell_count = nocts * 8 oct_counts = oct_handler.count_levels(max_level, 1, mask) level_counts = np.concatenate(([ 0, ], np.cumsum(oct_counts))) fc = oct_handler.fcoords(domain, mask, cell_count, level_counts.copy()) leavesb = oct_handler.count_leaves(mask) assert leaves == leavesb #Now take the fcoords, call them particles and recreate the same octree print "particle-based recreate" oct_handler2 = ParticleOctreeContainer(dd, dle, dre) oct_handler2.allocate_domains([nocts]) oct_handler2.n_ref = 1 #specifically make a maximum of 1 particle per oct oct_handler2.add(fc, 1)
class RAMSESDomainFile(object): _last_mask = None _last_selector_id = None def __init__(self, ds, domain_id): self.ds = ds self.domain_id = domain_id self.nvar = 0 # Set this later! num = os.path.basename( ds.parameter_filename).split(".")[0].split("_")[1] basename = "%s/%%s_%s.out%05i" % (os.path.abspath( os.path.dirname(ds.parameter_filename)), num, domain_id) for t in ['grav', 'hydro', 'part', 'amr']: setattr(self, "%s_fn" % t, basename % t) self._read_amr_header() self._read_hydro_header() self._read_particle_header() self._read_amr() _hydro_offset = None _level_count = None def __repr__(self): return "RAMSESDomainFile: %i" % self.domain_id def _is_hydro(self): ''' Does the output include hydro? ''' return os.path.exists(self.hydro_fn) @property def level_count(self): if self._level_count is not None: return self._level_count self.hydro_offset return self._level_count @property def hydro_offset(self): if self._hydro_offset is not None: return self._hydro_offset # We now have to open the file and calculate it f = open(self.hydro_fn, "rb") fpu.skip(f, 6) # It goes: level, CPU, 8-variable min_level = self.ds.min_level n_levels = self.amr_header['nlevelmax'] - min_level hydro_offset = np.zeros(n_levels, dtype='int64') hydro_offset -= 1 level_count = np.zeros(n_levels, dtype='int64') skipped = [] for level in range(self.amr_header['nlevelmax']): for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): header = (('file_ilevel', 1, 'I'), ('file_ncache', 1, 'I')) try: hvals = fpu.read_attrs(f, header, "=") except AssertionError: print "You are running with the wrong number of fields." print "If you specified these in the load command, check the array length." print "In this file there are %s hydro fields." % skipped #print "The last set of field sizes was: %s" % skipped raise if hvals['file_ncache'] == 0: continue assert (hvals['file_ilevel'] == level + 1) if cpu + 1 == self.domain_id and level >= min_level: hydro_offset[level - min_level] = f.tell() level_count[level - min_level] = hvals['file_ncache'] skipped = fpu.skip(f, 8 * self.nvar) self._hydro_offset = hydro_offset self._level_count = level_count return self._hydro_offset def _read_hydro_header(self): # If no hydro file is found, return if not self._is_hydro(): return if self.nvar > 0: return self.nvar # Read the number of hydro variables f = open(self.hydro_fn, "rb") fpu.skip(f, 1) self.nvar = fpu.read_vector(f, "i")[0] def _read_particle_header(self): if not os.path.exists(self.part_fn): self.local_particle_count = 0 self.particle_field_offsets = {} return f = open(self.part_fn, "rb") f.seek(0, os.SEEK_END) flen = f.tell() f.seek(0) hvals = {} attrs = (('ncpu', 1, 'I'), ('ndim', 1, 'I'), ('npart', 1, 'I')) hvals.update(fpu.read_attrs(f, attrs)) fpu.read_vector(f, 'I') attrs = (('nstar_tot', 1, 'I'), ('mstar_tot', 1, 'd'), ('mstar_lost', 1, 'd'), ('nsink', 1, 'I')) hvals.update(fpu.read_attrs(f, attrs)) self.particle_header = hvals self.local_particle_count = hvals['npart'] particle_fields = [("particle_position_x", "d"), ("particle_position_y", "d"), ("particle_position_z", "d"), ("particle_velocity_x", "d"), ("particle_velocity_y", "d"), ("particle_velocity_z", "d"), ("particle_mass", "d"), ("particle_identifier", "I"), ("particle_refinement_level", "I")] if hvals["nstar_tot"] > 0: particle_fields += [("particle_age", "d"), ("particle_metallicity", "d")] field_offsets = {} _pfields = {} for field, vtype in particle_fields: if f.tell() >= flen: break field_offsets["io", field] = f.tell() _pfields["io", field] = vtype fpu.skip(f, 1) self.particle_field_offsets = field_offsets self.particle_field_types = _pfields self.particle_types = self.particle_types_raw = ("io", ) def _read_amr_header(self): hvals = {} f = open(self.amr_fn, "rb") for header in ramses_header(hvals): hvals.update(fpu.read_attrs(f, header)) # That's the header, now we skip a few. hvals['numbl'] = np.array(hvals['numbl']).reshape( (hvals['nlevelmax'], hvals['ncpu'])) fpu.skip(f) if hvals['nboundary'] > 0: fpu.skip(f, 2) self.ngridbound = fpu.read_vector(f, 'i').astype("int64") else: self.ngridbound = np.zeros(hvals['nlevelmax'], dtype='int64') free_mem = fpu.read_attrs(f, (('free_mem', 5, 'i'), )) ordering = fpu.read_vector(f, 'c') fpu.skip(f, 4) # Now we're at the tree itself # Now we iterate over each level and each CPU. self.amr_header = hvals self.amr_offset = f.tell() self.local_oct_count = hvals['numbl'][self.ds.min_level:, self.domain_id - 1].sum() self.total_oct_count = hvals['numbl'][self.ds.min_level:, :].sum( axis=0) def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer(self.ds.domain_dimensions / 2, self.ds.domain_left_edge, self.ds.domain_right_edge) root_nodes = self.amr_header['numbl'][self.ds.min_level, :].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) fb = open(self.amr_fn, "rb") fb.seek(self.amr_offset) f = cStringIO.StringIO() f.write(fb.read()) f.seek(0) mylog.debug("Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum()) def _ng(c, l): if c < self.amr_header['ncpu']: ng = self.amr_header['numbl'][l, c] else: ng = self.ngridbound[c - self.amr_header['ncpu'] + self.amr_header['nboundary'] * l] return ng min_level = self.ds.min_level max_level = min_level nx, ny, nz = (((i - 1.0) / 2.0) for i in self.amr_header['nx']) for level in range(self.amr_header['nlevelmax']): # Easier if do this 1-indexed for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): #ng is the number of octs on this level on this domain ng = _ng(cpu, level) if ng == 0: continue ind = fpu.read_vector(f, "I").astype("int64") fpu.skip(f, 2) pos = np.empty((ng, 3), dtype='float64') pos[:, 0] = fpu.read_vector(f, "d") - nx pos[:, 1] = fpu.read_vector(f, "d") - ny pos[:, 2] = fpu.read_vector(f, "d") - nz #pos *= self.ds.domain_width #pos += self.dataset.domain_left_edge fpu.skip(f, 31) #parents = fpu.read_vector(f, "I") #fpu.skip(f, 6) #children = np.empty((ng, 8), dtype='int64') #for i in range(8): # children[:,i] = fpu.read_vector(f, "I") #cpu_map = np.empty((ng, 8), dtype="int64") #for i in range(8): # cpu_map[:,i] = fpu.read_vector(f, "I") #rmap = np.empty((ng, 8), dtype="int64") #for i in range(8): # rmap[:,i] = fpu.read_vector(f, "I") # We don't want duplicate grids. # Note that we're adding *grids*, not individual cells. if level >= min_level: assert (pos.shape[0] == ng) n = self.oct_handler.add(cpu + 1, level - min_level, pos, count_boundary=1) self._error_check(cpu, level, pos, n, ng, (nx, ny, nz)) if n > 0: max_level = max(level - min_level, max_level) self.max_level = max_level self.oct_handler.finalize() def _error_check(self, cpu, level, pos, n, ng, nn): # NOTE: We have the second conditional here because internally, it will # not add any octs in that case. if n == ng or cpu + 1 > self.oct_handler.num_domains: return # This is where we now check for issues with creating the new octs, and # we attempt to determine what precisely is going wrong. # These are all print statements. print "We have detected an error with the construction of the Octree." print " The number of Octs to be added : %s" % ng print " The number of Octs added : %s" % n print " Level : %s" % level print " CPU Number (0-indexed) : %s" % cpu for i, ax in enumerate('xyz'): print " extent [%s] : %s %s" % \ (ax, pos[:,i].min(), pos[:,i].max()) print " domain left : %s" % \ (self.ds.domain_left_edge,) print " domain right : %s" % \ (self.ds.domain_right_edge,) print " offset applied : %s %s %s" % \ (nn[0], nn[1], nn[2]) print "AMR Header:" for key in sorted(self.amr_header): print " %-30s: %s" % (key, self.amr_header[key]) raise RuntimeError def included(self, selector): if getattr(selector, "domain_id", None) is not None: return selector.domain_id == self.domain_id domain_ids = self.oct_handler.domain_identify(selector) return self.domain_id in domain_ids
class RAMSESDomainFile(object): _last_mask = None _last_selector_id = None def __init__(self, ds, domain_id): self.ds = ds self.domain_id = domain_id self.nvar = 0 # Set this later! num = os.path.basename(ds.parameter_filename).split("." )[0].split("_")[1] basename = "%s/%%s_%s.out%05i" % ( os.path.abspath( os.path.dirname(ds.parameter_filename)), num, domain_id) for t in ['grav', 'hydro', 'part', 'amr']: setattr(self, "%s_fn" % t, basename % t) self._read_amr_header() self._read_hydro_header() self._read_particle_header() self._read_amr() _hydro_offset = None _level_count = None def __repr__(self): return "RAMSESDomainFile: %i" % self.domain_id def _is_hydro(self): ''' Does the output include hydro? ''' return os.path.exists(self.hydro_fn) @property def level_count(self): if self._level_count is not None: return self._level_count self.hydro_offset return self._level_count @property def hydro_offset(self): if self._hydro_offset is not None: return self._hydro_offset # We now have to open the file and calculate it f = open(self.hydro_fn, "rb") fpu.skip(f, 6) # It goes: level, CPU, 8-variable min_level = self.ds.min_level n_levels = self.amr_header['nlevelmax'] - min_level hydro_offset = np.zeros(n_levels, dtype='int64') hydro_offset -= 1 level_count = np.zeros(n_levels, dtype='int64') skipped = [] for level in range(self.amr_header['nlevelmax']): for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): header = ( ('file_ilevel', 1, 'I'), ('file_ncache', 1, 'I') ) try: hvals = fpu.read_attrs(f, header, "=") except AssertionError: print("You are running with the wrong number of fields.") print("If you specified these in the load command, check the array length.") print("In this file there are %s hydro fields." % skipped) #print "The last set of field sizes was: %s" % skipped raise if hvals['file_ncache'] == 0: continue assert(hvals['file_ilevel'] == level+1) if cpu + 1 == self.domain_id and level >= min_level: hydro_offset[level - min_level] = f.tell() level_count[level - min_level] = hvals['file_ncache'] skipped = fpu.skip(f, 8 * self.nvar) self._hydro_offset = hydro_offset self._level_count = level_count return self._hydro_offset def _read_hydro_header(self): # If no hydro file is found, return if not self._is_hydro(): return if self.nvar > 0: return self.nvar # Read the number of hydro variables f = open(self.hydro_fn, "rb") fpu.skip(f, 1) self.nvar = fpu.read_vector(f, "i")[0] def _read_particle_header(self): if not os.path.exists(self.part_fn): self.local_particle_count = 0 self.particle_field_offsets = {} return f = open(self.part_fn, "rb") f.seek(0, os.SEEK_END) flen = f.tell() f.seek(0) hvals = {} attrs = ( ('ncpu', 1, 'I'), ('ndim', 1, 'I'), ('npart', 1, 'I') ) hvals.update(fpu.read_attrs(f, attrs)) fpu.read_vector(f, 'I') attrs = ( ('nstar_tot', 1, 'I'), ('mstar_tot', 1, 'd'), ('mstar_lost', 1, 'd'), ('nsink', 1, 'I') ) hvals.update(fpu.read_attrs(f, attrs)) self.particle_header = hvals self.local_particle_count = hvals['npart'] particle_fields = [ ("particle_position_x", "d"), ("particle_position_y", "d"), ("particle_position_z", "d"), ("particle_velocity_x", "d"), ("particle_velocity_y", "d"), ("particle_velocity_z", "d"), ("particle_mass", "d"), ("particle_identifier", "I"), ("particle_refinement_level", "I")] if hvals["nstar_tot"] > 0: particle_fields += [("particle_age", "d"), ("particle_metallicity", "d")] field_offsets = {} _pfields = {} for field, vtype in particle_fields: if f.tell() >= flen: break field_offsets["io", field] = f.tell() _pfields["io", field] = vtype fpu.skip(f, 1) self.particle_field_offsets = field_offsets self.particle_field_types = _pfields self.particle_types = self.particle_types_raw = ("io",) def _read_amr_header(self): hvals = {} f = open(self.amr_fn, "rb") for header in ramses_header(hvals): hvals.update(fpu.read_attrs(f, header)) # That's the header, now we skip a few. hvals['numbl'] = np.array(hvals['numbl']).reshape( (hvals['nlevelmax'], hvals['ncpu'])) fpu.skip(f) if hvals['nboundary'] > 0: fpu.skip(f, 2) self.ngridbound = fpu.read_vector(f, 'i').astype("int64") else: self.ngridbound = np.zeros(hvals['nlevelmax'], dtype='int64') free_mem = fpu.read_attrs(f, (('free_mem', 5, 'i'), ) ) ordering = fpu.read_vector(f, 'c') fpu.skip(f, 4) # Now we're at the tree itself # Now we iterate over each level and each CPU. self.amr_header = hvals self.amr_offset = f.tell() self.local_oct_count = hvals['numbl'][self.ds.min_level:, self.domain_id - 1].sum() self.total_oct_count = hvals['numbl'][self.ds.min_level:,:].sum(axis=0) def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer(self.ds.domain_dimensions/2, self.ds.domain_left_edge, self.ds.domain_right_edge) root_nodes = self.amr_header['numbl'][self.ds.min_level,:].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) fb = open(self.amr_fn, "rb") fb.seek(self.amr_offset) f = BytesIO() f.write(fb.read()) f.seek(0) mylog.debug("Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum()) def _ng(c, l): if c < self.amr_header['ncpu']: ng = self.amr_header['numbl'][l, c] else: ng = self.ngridbound[c - self.amr_header['ncpu'] + self.amr_header['nboundary']*l] return ng min_level = self.ds.min_level # yt max level is not the same as the RAMSES one. # yt max level is the maximum number of additional refinement levels # so for a uni grid run with no refinement, it would be 0. # So we initially assume that. max_level = 0 nx, ny, nz = (((i-1.0)/2.0) for i in self.amr_header['nx']) for level in range(self.amr_header['nlevelmax']): # Easier if do this 1-indexed for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): #ng is the number of octs on this level on this domain ng = _ng(cpu, level) if ng == 0: continue ind = fpu.read_vector(f, "I").astype("int64") fpu.skip(f, 2) pos = np.empty((ng, 3), dtype='float64') pos[:,0] = fpu.read_vector(f, "d") - nx pos[:,1] = fpu.read_vector(f, "d") - ny pos[:,2] = fpu.read_vector(f, "d") - nz #pos *= self.ds.domain_width #pos += self.dataset.domain_left_edge fpu.skip(f, 31) #parents = fpu.read_vector(f, "I") #fpu.skip(f, 6) #children = np.empty((ng, 8), dtype='int64') #for i in range(8): # children[:,i] = fpu.read_vector(f, "I") #cpu_map = np.empty((ng, 8), dtype="int64") #for i in range(8): # cpu_map[:,i] = fpu.read_vector(f, "I") #rmap = np.empty((ng, 8), dtype="int64") #for i in range(8): # rmap[:,i] = fpu.read_vector(f, "I") # We don't want duplicate grids. # Note that we're adding *grids*, not individual cells. if level >= min_level: assert(pos.shape[0] == ng) n = self.oct_handler.add(cpu + 1, level - min_level, pos, count_boundary = 1) self._error_check(cpu, level, pos, n, ng, (nx, ny, nz)) if n > 0: max_level = max(level - min_level, max_level) self.max_level = max_level self.oct_handler.finalize() def _error_check(self, cpu, level, pos, n, ng, nn): # NOTE: We have the second conditional here because internally, it will # not add any octs in that case. if n == ng or cpu + 1 > self.oct_handler.num_domains: return # This is where we now check for issues with creating the new octs, and # we attempt to determine what precisely is going wrong. # These are all print statements. print("We have detected an error with the construction of the Octree.") print(" The number of Octs to be added : %s" % ng) print(" The number of Octs added : %s" % n) print(" Level : %s" % level) print(" CPU Number (0-indexed) : %s" % cpu) for i, ax in enumerate('xyz'): print(" extent [%s] : %s %s" % \ (ax, pos[:,i].min(), pos[:,i].max())) print(" domain left : %s" % \ (self.ds.domain_left_edge,)) print(" domain right : %s" % \ (self.ds.domain_right_edge,)) print(" offset applied : %s %s %s" % \ (nn[0], nn[1], nn[2])) print("AMR Header:") for key in sorted(self.amr_header): print(" %-30s: %s" % (key, self.amr_header[key])) raise RuntimeError def included(self, selector): if getattr(selector, "domain_id", None) is not None: return selector.domain_id == self.domain_id domain_ids = self.oct_handler.domain_identify(selector) return self.domain_id in domain_ids
def _read_amr(self): """Open the oct file, read in octs level-by-level. For each oct, only the position, index, level and domain are needed - its position in the octree is found automatically. The most important is finding all the information to feed oct_handler.add """ self.oct_handler = RAMSESOctreeContainer(self.ds.domain_dimensions/2, self.ds.domain_left_edge, self.ds.domain_right_edge) root_nodes = self.amr_header['numbl'][self.ds.min_level,:].sum() self.oct_handler.allocate_domains(self.total_oct_count, root_nodes) fb = open(self.amr_fn, "rb") fb.seek(self.amr_offset) f = BytesIO() f.write(fb.read()) f.seek(0) mylog.debug("Reading domain AMR % 4i (%0.3e, %0.3e)", self.domain_id, self.total_oct_count.sum(), self.ngridbound.sum()) def _ng(c, l): if c < self.amr_header['ncpu']: ng = self.amr_header['numbl'][l, c] else: ng = self.ngridbound[c - self.amr_header['ncpu'] + self.amr_header['nboundary']*l] return ng min_level = self.ds.min_level # yt max level is not the same as the RAMSES one. # yt max level is the maximum number of additional refinement levels # so for a uni grid run with no refinement, it would be 0. # So we initially assume that. max_level = 0 nx, ny, nz = (((i-1.0)/2.0) for i in self.amr_header['nx']) for level in range(self.amr_header['nlevelmax']): # Easier if do this 1-indexed for cpu in range(self.amr_header['nboundary'] + self.amr_header['ncpu']): #ng is the number of octs on this level on this domain ng = _ng(cpu, level) if ng == 0: continue ind = fpu.read_vector(f, "I").astype("int64") fpu.skip(f, 2) pos = np.empty((ng, 3), dtype='float64') pos[:,0] = fpu.read_vector(f, "d") - nx pos[:,1] = fpu.read_vector(f, "d") - ny pos[:,2] = fpu.read_vector(f, "d") - nz #pos *= self.ds.domain_width #pos += self.dataset.domain_left_edge fpu.skip(f, 31) #parents = fpu.read_vector(f, "I") #fpu.skip(f, 6) #children = np.empty((ng, 8), dtype='int64') #for i in range(8): # children[:,i] = fpu.read_vector(f, "I") #cpu_map = np.empty((ng, 8), dtype="int64") #for i in range(8): # cpu_map[:,i] = fpu.read_vector(f, "I") #rmap = np.empty((ng, 8), dtype="int64") #for i in range(8): # rmap[:,i] = fpu.read_vector(f, "I") # We don't want duplicate grids. # Note that we're adding *grids*, not individual cells. if level >= min_level: assert(pos.shape[0] == ng) n = self.oct_handler.add(cpu + 1, level - min_level, pos, count_boundary = 1) self._error_check(cpu, level, pos, n, ng, (nx, ny, nz)) if n > 0: max_level = max(level - min_level, max_level) self.max_level = max_level self.oct_handler.finalize()
from __future__ import print_function from yt.geometry.fake_octree import create_fake_octree from yt.geometry.oct_container import RAMSESOctreeContainer, ParticleOctreeContainer import numpy as np nocts= 3 max_level = 12 dn = 2 dd = np.ones(3,dtype='i4')*dn dle = np.ones(3,dtype='f8')*0.0 dre = np.ones(3,dtype='f8') fsub = 0.25 domain = 1 oct_handler = RAMSESOctreeContainer(dd,dle,dre) leaves = create_fake_octree(oct_handler, nocts, max_level, dd, dle, dre, fsub) mask = np.ones((nocts,8),dtype='bool') cell_count = nocts*8 oct_counts = oct_handler.count_levels(max_level, 1, mask) level_counts = np.concatenate(([0,],np.cumsum(oct_counts))) fc = oct_handler.fcoords(domain,mask,cell_count, level_counts.copy()) leavesb = oct_handler.count_leaves(mask) assert leaves == leavesb #Now take the fcoords, call them particles and recreate the same octree print("particle-based recreate") oct_handler2 = ParticleOctreeContainer(dd,dle,dre) oct_handler2.allocate_domains([nocts]) oct_handler2.n_ref = 1 #specifically make a maximum of 1 particle per oct oct_handler2.add(fc, 1) print("added particles")