def pressure_scale_height(field, data): """Scale height (H) for cylindrical coordinates. WARN: cylindrical_r is not sound for other coord systems. approximates gravity by U/r H = kT/mg m = mean molec weight = rho * N_A/(n_I+n_e) n_I = rho*N_A \Sigma_i x_i / A_i n_e = rho*N_A \Sigma_i x_i * Z_i / A_i """ _, ps, ns, ms = splitSpecies(_alphas) # ms = np.array(len(_alphas)*[np.array(ms)]) # ps = np.array(len(_alphas)*[np.array(ps)]) ms = np.array(ms) ps = np.array(ps) xms = [data['flash', s].v for s in _alphas] xms = np.array(xms) # 13 cell*cell*cell blocks nions = [xms[i]/ms[i] for i in range(len(_alphas))] nions = np.array(nions) neles = [xms[i]/ms[i]*ps[i] for i in range(len(_alphas))] neles = np.array(neles) totalnele = np.sum(neles) totalnion = np.sum(nions) mu_ele = 1/(totalnele+totalnion) num = data['kT'].v g = -data['gpot'].v/data['cylindrical_r'].v return num/g/mu_ele
def extractVariables(source, destination, variables=['temp']): """creates a new hdf5 FLASH file with a reduced set of variables. Args: source(str): input filename. destination(str): output filename. variables(str list): list of named variables to extract. """ finn = h5py.File(source, 'r') # essential mesh data for the FLASH file structure struct = [ 'bflags', 'block size', 'bounding box', 'coordinates', 'gid', 'gsurr_blks', 'integer runtime parameters', 'integer scalars', 'logical runtime parameters', 'logical scalars', 'node type', 'real runtime parameters', 'real scalars', 'refine level', 'sim info', 'string runtime parameters', 'string scalars', 'unknown names', 'which child' ] struct += variables # turn selected tags to bytes newunks = np.array(variables, dtype=np.bytes_) with h5py.File(destination, 'w') as otp: for key in finn.keys(): if key in struct: print('Wrote: ', key) # reduce the variables to selected ones. if key == 'unknown names': otp.create_dataset('unknown names', data=[newunks]) else: otp.copy(finn[key], dest='/{}'.format(key))
def mean_molec_weight(field, data): """Mean molecular weight for alpha mixture m = mean molec weight = rho * N_A/(n_I+n_e) n_I = rho*N_A \Sigma_i x_i / A_i n_e = rho*N_A \Sigma_i x_i * Z_i / A_i """ _, ps, ns, ms = splitSpecies(_alphas) ms = np.array(ms) ps = np.array(ps) xms = [data['flash', s].v for s in _alphas] xms = np.array(xms) # 13 cell*cell*cell blocks nions = [xms[i]/ms[i] for i in range(len(_alphas))] nions = np.array(nions) neles = [xms[i]/ms[i]*ps[i] for i in range(len(_alphas))] neles = np.array(neles) totalnele = np.sum(neles) totalnion = np.sum(nions) return 1/(totalnele+totalnion)
def snipProf(orig, cut, byM=False, left=True, keys=[]): """ cuts a profile, returning a standalone profile obj for conv: center is 0, edge is -1. """ abscissa = orig.masses if byM else orig.radius npabs = np.array(abscissa) flow = operator.le(npabs, cut) if left else operator.ge(npabs, cut) cells = np.where(flow) # start block with essential properties (all dmat have these 2). nra = orig.radius[cells] nde = orig.density[cells] dblock = np.column_stack([nra, nde]) keys = orig.filekeys for k in keys[2:]: dblock = np.column_stack((dblock, getattr(orig, k)[cells])) return dataMatrix([keys, dblock])
def snipProf(orig, cut, byM=False, left=True, edgecell=False): """cuts a profile, returning a new profile obj. conv: center is 0, edge is -1. Args: orig(dataMatrix): dMatrix object to cut. cut(float): cut coordinate. byM(bool): specify cut is by mass coordinate. left(bool): return data at the left/right of the cut. Returns: (dataMatrix): new dMatrix object. """ abscissa = orig.masses if byM else orig.radius npabs = np.array(abscissa) flow = operator.le(npabs, cut) if left else operator.ge(npabs, cut) if np.any(flow) is False: print('Cut outside the profile, returning whole profile') return orig allcells = np.where(flow) # remove edge cell if edgecell: cells = (allcells[0][:], ) if left else (allcells[0][0:], ) else: cells = (allcells[0][:], ) if left else (allcells[0][0:], ) # start block with essential properties (all dmat have these 2). nra = orig.radius[cells] nde = orig.density[cells] dblock = np.column_stack([nra, nde]) keys = orig.filekeys rem = [] for i, k in enumerate(keys): if k in orig.rnames or k in orig.dnames: continue elif k in orig.mnames: rem.append(i) continue dblock = np.column_stack((dblock, getattr(orig, k)[cells])) for index in rem: del keys[index] return dataMatrix([keys, dblock])
def wedge3d(chkp, elevation, depth, reference='x', fields=[], antipode=False): """cut a wedge in a 3d rectangular domain to perform velocity vs mass fraction measurements. default fields: vx, vy, vz, cell_mass and species Args: fname(str): file name elevation(float): equator-north pole wedge angle. depth(float): equator-south pole wedge angle. reference(str): equinox reference for the equator. fields(str list): override default fields. antipode(bool): invert selection, antipodal wedge. Returns: (tuple of np.arrays): raw data sorted by field. """ ds = yt.load(chkp) for f in fields: if f in dir(ytf): meta = getattr(ytf, '_' + f) yt.add_field(("flash", f), function=getattr(ytf, f), **meta) domx, domy, domz = ds.domain_width.value rad = 100 * np.max(ds.domain_width.value) # huge radius to grab all cells. inv = -1.0 if antipode else 1.0 # flip selection tvec, bvec = { 'x': [(0.0, 0.5 * domy, 0.5 * domz), (0.0, 0.5 * domy, -0.5 * domz)], 'y': [(0.5 * domx, 0.0, 0.5 * domz), (-0.5 * domx, 0.0, 0.5 * domz)], 'z': [(0.5 * domx, 0.5 * domy, 0.0), (0.5 * domx, -0.5 * domy, 0.0)] }[reference] topv = np.array(tvec) botv = np.array(bvec) if depth * elevation < 0.0: # in this case we are on a quadrant if depth < 0.0: # upper right, use 2 bottom cylinders: # normal bot cylinder up to abs(depth) equ = 45 - abs(depth) alt = np.deg2rad(equ) rm = rot(-alt, reference) normal = rm.dot(botv) height = np.cos(alt) * np.sqrt(botv.dot(botv)) center = botv * inv cylinder1 = ds.disk(center=ds.arr(center, "code_length"), normal=ds.arr(normal, "code_length"), radius=(_radiusMult * domy, "code_length"), height=(height, "code_length")) # second cylinder up to elevation but flipped to grab the wedge equ = 45 - elevation alt = np.deg2rad(equ) rm = rot(-alt, reference) normal = rm.dot(botv) height = np.cos(alt) * np.sqrt(botv.dot(botv)) center = -botv * inv cylinder2 = ds.disk(center=ds.arr(center, "code_length"), normal=ds.arr(normal, "code_length"), radius=(_radiusMult * domy, "code_length"), height=(height, "code_length")) else: # lower right, use 2 top cylinders: # first top goes down to depth and in inverted equ = 45 - depth # 45 degree offset from center-origin reference dep = np.deg2rad(equ) rm = rot(dep, reference) normal = rm.dot(topv) height = np.cos(dep) * np.sqrt(topv.dot(topv)) center = topv * inv cylinder1 = ds.disk(center=ds.arr(center, "code_length"), normal=ds.arr(normal, "code_length"), radius=(rad, "code_length"), height=(height, "code_length")) # second top cylinder goes down to abs(elevation) # 45 degree offset from center-origin reference equ = 45 - abs(elevation) dep = np.deg2rad(equ) rm = rot(dep, reference) normal = rm.dot(topv) height = np.cos(dep) * np.sqrt(topv.dot(topv)) center = -topv * inv cylinder2 = ds.disk(center=ds.arr(center, "code_length"), normal=ds.arr(normal, "code_length"), radius=(rad, "code_length"), height=(height, "code_length")) else: # default wedge covering the equator # top cylinder equ = 45 - depth # 45 degree offset from center-origin reference dep = np.deg2rad(equ) rm = rot(dep, reference) normal = rm.dot(topv) height = np.cos(dep) * np.sqrt(topv.dot(topv)) center = topv * inv cylinder1 = ds.disk(center=ds.arr(center, "code_length"), normal=ds.arr(normal, "code_length"), radius=(rad, "code_length"), height=(height, "code_length")) # bottom cylinder equ = 45 - elevation # 45 degree offset from center-origin reference alt = np.deg2rad(equ) rm = rot(-alt, reference) normal = rm.dot(botv) height = np.cos(alt) * np.sqrt(botv.dot(botv)) center = botv * inv cylinder2 = ds.disk(center=ds.arr(center, "code_length"), normal=ds.arr(normal, "code_length"), radius=(rad, "code_length"), height=(height, "code_length")) wedge = ds.intersection([cylinder1, cylinder2]) # get fields and data from data file if not fields: _, species = getFields(ds.field_list) fields = ['velx', 'vely', 'velz', 'cell_mass'] + species # rawd 0 1 2 3 fixed. # offset = 4 # ask yt for data, as always this takes forever. rawd = [] for f in fields: rawd.append(wedge[f].value) return rawd, species # WARNING: this might be humongous. else: rawd = [] for f in fields: rawd.append(wedge[f].value) return rawd
def getYields(fname, subsetR=0.0): """returns time, summed masses and species in a flash otp file. all units are msun or cgs. 1D assumes spherical geometry 2D assumes cylindrical geometry and trims cart_ from filename. Args: fname(str): filename to inspect. subsetR(float): radius cutoff for extraction. Returns: time (float) [s], species names: (list of str), masses: (float list) [msun] """ if 'cart' in fname: stem, bud = os.path.split(fname) filename = os.path.join(stem, bud[5:]) else: filename = fname ds = yt.load(filename) if subsetR: log.warning('R subset for yields: {:.2E}'.format(subsetR)) ad = ds.sphere([0.0, 0.0, 0.0], (subsetR, 'cm')) else: ad = ds.all_data() _, species = getFields(ds.field_list) species = [s.ljust(4) for s in species] # 2d glitches due to dz being nonsensical if ds.parameters['dimensionality'] == 1: try: dx = ad['path_element_x'].value x = ad['x'].value except YTFieldNotFound: dx = ad['path_element_r'].value x = ad['r'].value fac = 4.0 / 3.0 * np.pi if len(x) > 1: rdiff = np.diff(x) rdiff = np.append(rdiff, rdiff[-1]) skewed = 0.5 * rdiff + x skewed = np.insert(skewed, 0, 0.0) rcub = skewed**3 vols = fac * np.diff(rcub) else: vols = np.array([fac * ad['dr'].value]) cell_masses = vols * ad['density'].value / msol msunMs = [] for sp in species: msunMs.append(np.sum(cell_masses * ad[sp].value)) log.warning('Assumed spherical cells for volume') elif ds.parameters['dimensionality'] == 2: log.warning('Cylindrical volume cells') masses = ad.quantities.weighted_average_quantity(species, 'cell_mass') total = ad.quantities.total_mass() msunMs = [m.value * total[0].value / msol for m in masses] else: masses = ad.quantities.weighted_average_quantity(species, 'cell_mass') total = ad.quantities.total_mass() msunMs = [m.value * total[0].value / msol for m in masses] return ds.current_time.value, species, msunMs