Example #1
0
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
Example #2
0
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))
Example #3
0
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)
Example #4
0
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])
Example #5
0
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])
Example #6
0
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
Example #7
0
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