예제 #1
0
def writeGroupAscii(group='All', filename='groupAscii.dat'):
    """Writes out a tipsy-ascii file for the group (filename='groupAscii.dat')."""
    numStars = charm.getNumParticles(group,'star')
    numGas   = charm.getNumParticles(group,'gas')
    numDark  = charm.getNumParticles(group,'dark')
    numTotal = numStars + numGas + numDark
    #===========================================================================
    # This region outputs the ascii file to be read in by tipsy
    #===========================================================================
    f = open(filename, 'w') # overwrites pre-existing file
    f.write(str(numTotal) + ' ' + str(numGas) + ' ' + str(numStars))
    f.write('\n3')
    f.write('\n'+ str(charm.getTime())+ '\n')
    f.close()
    for each in ['star','dark','gas']:charm.createScalarAttribute(each, 'tmpWorking')
    def writeAndAppend(attribute):
        charm.writeGroupArray('tmpGalBox', attribute, '/tmp/out.tmp')
        os.system('tail -n +2 /tmp/out.tmp >> ' + filename)
        return
    families = ['gas','dark','star']
    for each in families:
        charm.createGroup_Family('tmpGalBox', 'galBox', each)
        writeAndAppend('mass')
    # Positions
    for i in range(0,3):
        for each in families:
            charm.createGroup_Family('tmpGalBox', 'galBox', each)
            charm.runLocalParticleCodeGroup('tmpGalBox', vectorWriter, ('pos', i))
            writeAndAppend('tmpWorking')
    # Velocities
    for i in range(0,3):
        for each in families:
            charm.createGroup_Family('tmpGalBox', 'galBox', each)
            charm.runLocalParticleCodeGroup('tmpGalBox', vectorWriter, ('vel', i))
            writeAndAppend('tmpWorking')
    # Star and dark softening
    for each in ['dark', 'star']:
        charm.createGroup_Family('tmpGalBox', 'galBox', each)
        writeAndAppend('softening')        
    # Gas attributes
    charm.createGroup_Family('tmpGalBox', 'galBox', 'gas')
    for each in ['density','temperature','softening','metals']:
        writeAndAppend(each)
    #Star stuff
    charm.createGroup_Family('tmpGalBox', 'galBox', 'star')
    for each in ['metals','formationtime']:
        writeAndAppend(each)
    #potential
    for each in families:
        charm.createGroup_Family('tmpGalBox', 'galBox', each)
        writeAndAppend('potential')
    charm.deleteGroup('tmpGalBox')
    #print 'num lines in ' + filename + ' should be: ' + str(9*numTotal+3*numGas+2*numStars+3)
    return
예제 #2
0
def getEpsilonDist(group='gal', nBins=50, epsCut=2., center='pot'):
    """Returns a histogram of dimension 2 x nbins of stellar epsilons (jz/jcirc) and mass-fraction.  epsCut defines the histogram bound in both directions. Center can be either 'pot' or 'com'"""
    numRotBins   = 400 #number of points at which we linearly interpolate 
    radiusVCM    = 0.25 #fraction of group radius to use when calculating COM velocity
    radiusAngMom = 0.25 #fraction of group radius to use when calculating stellar angular momentum
    
    
    a = charm.getTime()
    if ((group in charm.getGroups()==False)) & (group !='gal'):
        print "Group does not exist, please try again."
        return
    if (group == 'gal'): 
        rgal = quesoConfig.rgalFraction*virialgroup.getVirialGroup()
        center=findcenter.findCenter(group2='virialGroup', method=center)
        charm.createGroupAttributeSphere('gal', 'All', 'position', center[0], center[1], center[2], rgal)
    else:
        center=findcenter.findCenter(group2=group, method=center)
        
    # Find maximum radius
    charm.createGroup_Family('tmp',group,'star')
    maxRad = getgroupradius.getGroupRadius('tmp', center)
    massDist = [0]*(numRotBins+1)
    rad = [0]*(numRotBins+1)
    radialStep = maxRad/numRotBins
    #populate mass bins
    for i in range(numRotBins+1): 
        charm.createGroupAttributeSphere('tmp', 'All', 'position', center[0], center[1], center[2], radialStep*i)
        massDist[i]  = charm.getAttributeSum('tmp','star','mass')
        massDist[i] += charm.getAttributeSum('tmp','dark','mass')
        massDist[i] += charm.getAttributeSum('tmp','gas' ,'mass')
        #Note: I tried shells instead of spheres and it made no real difference.
        rad[i] = radialStep*i
        
    vCM = getVelCMStars(center2=center, radius=radiusVCM*maxRad) #COM velocity
    angMomVec = getNormalStarAngMom(center2=center, radius=radiusAngMom*maxRad, comVel=vCM) #Ang Mom Velocity
    #vCM = getVelCMStars(center2=center, radius=10/(a*quesoConfig.kpcunit)) #COM velocity
    #angMomVec = getNormalStarAngMom(center2=center, radius=6/(a*quesoConfig.kpcunit), comVel=vCM) #Ang Mom Velocity
    
    param = (center, vCM, angMomVec, maxRad, numRotBins,massDist, nBins,epsCut)
    charm.createGroupAttributeSphere('tmp', 'All', 'position', center[0], center[1], center[2], maxRad)
    charm.createGroup_Family('tmp',group,'star')
    #calc total stellar mass for mass weighted average
    reduceResult = charm.reduceParticle('tmp', mapEpsilon, reduceEpsilon, param) 
    sMass = charm.getAttributeSum('tmp','star', 'mass')
    epsilonDist = [0]*nBins
    eps  = [0]*nBins
    for i in range(nBins): eps[i] = -epsCut+ 2*epsCut/nBins*(i)
    for i in range(len(reduceResult)):
        try:
            bin = reduceResult[i][0]
            epsilonDist[bin] = reduceResult[i][1]/sMass #return the mass fraction
        except:{}
    return (eps, epsilonDist)
예제 #3
0
def calcGalacticCoordinates(angMomGroup=None, center ='pot'):
    '''Assigns particles a position in the galactic coordinate system. galVelocity = (v+Hr).  angMomGroup'''
    #===========================================================================
    # --Overview--
    # 1.Form transformation matrix
    # 2.Translate the coordinates to the center of the galaxy (or COM velocity)
    # 3.Rotate the coordinate system to be aligned with the angular momentum vector
    # 4.Write information to vector attributes
    #===========================================================================
    if ((angMomGroup in charm.getGroups())==False) & (angMomGroup!=None):
        print "Group does not exist, please try again."
        return
    ##############################
    # Actual Routine
    ##############################
    if (angMomGroup==None):
        angMomGroup = 'angMomGroup'
        cnt = findcenter.findCenter(method=center)
        virialRadius = virialgroup.getVirialGroup()
        charm.createGroupAttributeSphere('angMomGroup', 'All', 'position', cnt[0], cnt[1], cnt[2], virialRadius*quesoConfig.rgalFraction)
        charm.createGroup_Family('angMomGroup', 'angMomGroup', 'gas')
        charm.createGroup_AttributeRange('angMomGroup', 'angMomGroup', 'temperature', 0, quesoConfig.coldGasTemp)
    else: 
        cnt = findcenter.findCenter(group2=angMomGroup,method=center)
        
    angmom.getAngMomVector(group=angMomGroup,center=center)
    # Transformation Matrix
    galZ = vectormath.normalizeVector(angmom.getAngMomVector(group=angMomGroup,center=center))
    galX = vectormath.normalizeVector(vectormath.crossVectors((0,1,0),galZ))
    galY = vectormath.normalizeVector(vectormath.crossVectors(galZ,galX))
    transMatrix = (galX,
                   galY,
                   galZ)
    
    fHubble       = quesoConfig.fHubble0*math.sqrt(quesoConfig.omega0/charm.getTime()**3+(1-quesoConfig.omega0))
    # Galactic Position                    
    charm.createVectorAttribute('star','galPosition')
    charm.createVectorAttribute('gas', 'galPosition')
    charm.createVectorAttribute('dark','galPosition')
    param = (cnt, transMatrix)
    charm.runLocalParticleCodeGroup('All', calcGalPosition, param)
    # Galactic velocity
    vCM=angmom.getVelCM(angMomGroup)
    param = (cnt, transMatrix,vCM, fHubble)
    charm.createVectorAttribute('star','galVelocity')
    charm.createVectorAttribute('gas', 'galVelocity')
    charm.createVectorAttribute('dark','galVelocity')
    charm.runLocalParticleCodeGroup('All', calcGalVelocity, param)
    return
예제 #4
0
def SFRSurfaceProfile(minRadius=.1, numBins=50,tstep='00512',nbins=500):
    """Returns the list of tuples (radius, SFR, diskSFR, bulgeSFR) in solar masses/year! (for the 0.5Gyr preceding each time)"""
    #read in initial masses from file
    filename = quesoConfig.dataDir + quesoConfig.preTimestepFilename + tstep + ".massform"
    charm.readTipsyArray(filename,'initialMass')
    
    virialRadius = virialgroup.getVirialGroup()
    rgal = quesoConfig.rgalFraction*virialRadius
    center = findcenter.findCenter()       
    radialStep  = ((math.log10(rgal)-math.log10(minRadius))/(float(numBins)-1))
    simTime = getSimTime(timestep=tstep)/quesoConfig.timeunit #time in simulation units
    sfr = [[]]*numBins
    #initialize relevant attributes
    galcoord.calcGalacticCoordinates()
    
    #create sphere of stars
    charm.createGroupAttributeSphere('galStar', 'All', 'position', center[0], center[1], center[2], rgal) 
    charm.createGroup_Family('galStar', 'galStar', 'star')
    formHigh = simTime
    formLow  = formHigh-quesoConfig.sfrLookback/quesoConfig.timeunit
    param = (formLow, formHigh, radialStep, quesoConfig.kpcunit*charm.getTime(), minRadius)
    reduceResult = charm.reduceParticle('galStar' , mapSFRProfile, reduceSFRProfile, param)
    print reduceResult
    print (formLow,formHigh)
    maxbin=0
    
    for i in range(0,len(reduceResult)):
        if (reduceResult[i][0]>maxbin):maxbin=reduceResult[i][0]
    for i in range(0,len(reduceResult)):
        radiusOut = math.pow(10, radialStep*reduceResult[i][0])
        radiusInside = math.pow(10, radialStep*(reduceResult[i][0]-1))
        radius = (radiusOut+radiusInside)/2
        area  = math.pi*(radiusOut**2-radiusInside**2)
        formationRate      = reduceResult[i][1]*quesoConfig.msolunit/quesoConfig.sfrLookback/area #msolar/yr/kpc^2
        bin = reduceResult[i][0]+numBins-maxbin-1
        sfr[bin]=(radius, formationRate)
        print sfr[bin]
    for i in range(0,numBins):
        if (sfr[i] == []):
            radiusOut = math.pow(10, radialStep*(i+1))
            radiusInside = math.pow(10, radialStep*i)
            radius = (radiusOut+radiusInside)/2
            sfr[i]=(radius,0,0,0) 
    sfrData = [[],[]]        
    for i in range(len(sfr)):
        sfrData[0].append(sfr[i][0])
        sfrData[1].append(sfr[i][1])
    return sfrData
예제 #5
0
def getMomentInertiaTensor(group2,center='pot'):
    '''Return the moment of inertia tensor for given group.  center can be 'pot' or 'com'.  This is in physical units.
        [[Ixx, Ixy, Ixz],
         [Iyx, Iyy, Iyz],
         [Izx, Izy, Izz]]
    '''
    group = group2
    if ((group2 in charm.getGroups())==False):
        print "Group does not exist, please try again."
        return
    center = findcenter.findCenter(group2=group,method=center)
    triangleTensor = charm.reduceParticle(group , mapMomentInertiaTensor, reduceMomentInertiaTensor, center)[0][1]
    fullTensor = [[0]*3,[0]*3,[0]*3]
    units = quesoConfig.msolunit*((charm.getTime()*quesoConfig.kpcunit)**2)
    fullTensor[0] = vectormath.multVectorScalar(units, triangleTensor[0][0:3])
    fullTensor[1] = vectormath.multVectorScalar(units, [triangleTensor[0][1],triangleTensor[1][0],triangleTensor[1][1]])
    fullTensor[2] = vectormath.multVectorScalar(units, [triangleTensor[0][2],triangleTensor[1][1],triangleTensor[2][0]])
    return fullTensor
예제 #6
0
def getHalfMassRadius(group, center='pot') :
    """Returns the current stellar half mass radius."""
    #get the current galactic stellar mass
    rgal = 0.1*virialgroup.getVirialGroup()
    center = findcenter.findCenter(group2=group,method=center)
    halfMass = getFamilyAttributeSum(center,rgal,'star','mass')/2.0
    if (halfMass == 0 ): 
        print "Halfmass is zero inside rgal.  Are there stars inside rgal yet?." 
        return (0,0)
    #Bisection Method to locate half mass
    epsilon = .01
    count = 0
    maxIterations = 50
    a = charm.getTime()
    leftr = .1/(a*quesoConfig.kpcunit)
    rightr = 50/(a*quesoConfig.kpcunit)
    midpoint = (leftr + rightr)/2.0
    leftMass  = getFamilyAttributeSum(center,leftr   ,'star','mass')-halfMass  #Initialize values
    rightMass = getFamilyAttributeSum(center,rightr  ,'star','mass')-halfMass #offset to find root  
    midMass   = getFamilyAttributeSum(center,midpoint,'star','mass')-halfMass #offset so we can find root
    #Bisection to find halfmass radius using initialMass and mass
    #Run until values converge within epsilon or reach max count
    while (count<maxIterations) and (math.fabs((leftMass-rightMass)/halfMass) > epsilon*2.0):
        midpoint = (leftr + rightr)/2.0
        
        #if (math.fabs(leftMass-rightMass)/halfMass < 4*epsilon):break
        leftMass = getFamilyAttributeSum(center,leftr   ,'star','mass')-halfMass  #Initialize values
        rightMass= getFamilyAttributeSum(center,rightr  ,'star','mass')-halfMass #offset to find root  
        midMass  = getFamilyAttributeSum(center,midpoint,'star','mass')-halfMass #offset so we can find root
        #print str((leftMass,midMass,rightMass)) + "    " + str(math.fabs(leftMass-rightMass)/halfMass) +str((leftr,midpoint,rightr))
        if (leftMass*midMass<0)   : rightr = midpoint
        elif (rightMass*midMass<0): leftr  = midpoint
        elif (midMass==0)         : break
        elif (leftMass*midMass>0) and (rightMass*midMass>0):
            print "\nStellar half mass radius will not converge. Try larger bounds."
            return
        count += 1
    #Don't get stuck in a loop
    if (count==maxIterations): 
        print "\nDid not converge in " + str(maxIterations) + " iterations.  Try smaller bounds or raise epsilon in source."
        return
    resultVec=midpoint #already in units of kpc taking into account the expansion factor
    #print resultVec[i]
    return resultVec
예제 #7
0
def profile(group='All', center='pot', family='all', projection='sph', bin_type='log', nbins=30, filename='profile.DAT', min_radius=0., fit_radius=0.) :
  """Perform the Tipsy profile() function.
    
    profile is a command that produces a file of  name,  file-
    name,  that  contains various physical profiles as a func-
    tion of radius for particles of type particle in group.

    The  center  of the radial distribution is taken to be the
    center of mass of the particles of the  type  particle  in
    group center. If  the  string  "pot"  is given  instead of
    a  group  name for  the  argument center, the  particle in
    group  with  the  lowest  potential  energy is used as the
    center of the radial bins.

    The projection argument refers to the shape  of  the  bins
    and  the bin_type argument refers to how the particles are
    binned, either linearly or log in radius.  There are nbins
    bins  distributed  equally  in either radius or log radius
    between min_radius and the size of group.

    The  output file has the following columns: radius, number
    in bin, density, cumulative mass (M(<r)), circular  veloc-
    ity (sqrt(M(<r)/r)), radial velocity, radial velocity dis-
    persion, tangential velocity, tangential velocity  disper-
    sion,  specific  angular momentum (j),j_theta, j_phi.  The
    j_theta and j_phi angles specify the direction of the spe-
    cific  angular  momentum vector (in degrees). If family is
    is either gas,  baryon, or all,  four  additional  columns
    containing the mean mass weighted gas density, mass weigh-
    ted gas temperature, mass weighted gas pressure, and  mass
    weighted  gas  entropy  are  added.  If particle is either
    star, baryon, or  all  an additional column containing the
    stellar  luminosity  in the Johnson V band is added.  This
    is  calculated  using  the  ages  of  the  star  particles
    as in Katz (Ap.J. 391: 502, 1992).
    
    Note: some rarer configuration options are not implemented
    e.g. non-uniform UV for star luminosity calculation."""
    
  try:
    import charm
    # check initialization state of meanmwt attribute
    if family in ['all', 'gas', 'baryon'] and not 'meanmwt' in charm.getAttributes('gas') :
        print 'Attribute meanmwt not initialized. Initializing...'
        import load_meanmwt
        load_meanmwt.do_meanmwt()
    print '\n'
    # these should be moved to tipsyf
    # fn to take the dot product of two vectors in R3
    def dotprod(a, b) :
        return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
    # fn to take the cross product of two vectors in R3
    def crossprod(a, b) :
        return [a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]]
    # fn to multiply a vector v by a scalar c
    def scalevec(c, v) :
        return [c * v[0], c * v[1], c * v[2]]
    # fn to add two vectors
    def addvec(a, b) :
        return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
    # fn to subtract vector b from vector a
    def subvec(a, b) :
        return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
    # fn to find the length of a vector
    def vlength(a) :
        import math
        return math.sqrt(pow(a[0], 2) + pow(a[1], 2) + pow(a[2], 2))
    # fn to combine two vectors, weighting by their corresponding mass scalars
    def weightvecs(m1, x1, m2, x2) :
        return [(x1[0]*m1 + x2[0]*m2)/(m1+m2), (x1[1]*m1 + x2[1]*m2)/(m1+m2), (x1[2]*m1 + x2[2]*m2)/(m1+m2)]
    
    # scrub input
    # check if simulation loaded, store group list
    groups = charm.getGroups()
    if groups == None :
        raise StandardError('Simulation not loaded')
    # case is inconsistent between groups and families, work for either
    if group == 'all' :
        group = 'All'
    if family == 'All' :
        family = 'all'
    # deal with group or center group does not exist
    if group not in groups :
        raise StandardError('Group does not exist!')
    if (center not in groups) and (center != 'pot') :
        raise StandardError('Center group does not exist!')
    # set up families iterator and throw family related exceptions
    families = charm.getFamilies()
    if families == None :
        raise StandardError('Simulation loaded but no families present.')
    isbaryon = 0
    if family == 'baryon' :
        isbaryon = 1
        if 'dark' in families:
            families.remove('dark')
        if len(families) == 0 :
            raise StandardError('No baryon particles present in simulation.')
    if (family != 'all') and (family != 'baryon') :
        if family not in families :
            raise StandardError('Family not present in simulation.')
        else :
            families = [family]
    if len(families) == 0 :
        raise StandardError('List of families to process has zero length.')
    # create groups containing one family each, store names in famgroups list
    famgroups = []
    for each in families :
        famgroup = group + 'FAM' + each
        charm.createGroup_Family(famgroup, group, each)
	if charm.getNumParticles(famgroup, each) != 0 :
            famgroups += [famgroup]
    if len(famgroups) == 0 :
        raise StandardError('No particles in group of selected type.')
    # validate other inputs
    if bin_type == 'linear' :
        bin_type = 'lin'
    elif bin_type == 'logarithmic' :
        bin_type = 'log'
    elif bin_type not in ['lin', 'log'] :
        raise StandardError('Value of bin_type must be lin or log.')
    if (int(nbins) != nbins) or (nbins < 1) :
        raise StandardError('Value of nbins must be a positive integer.')
    if not min_radius >= 0 :
        raise StandardError('Value of min_radius cannot be negative.')
    if min_radius == 0 and bin_type == 'log' :
        min_radius = config.LOG_MIN
        print 'Parameter min_radius set to ' + str(min_radius) + ' to accomodate logarithmic binning.'
    if not fit_radius >= 0 :
        raise StandardError('Value of fit_radius cannot be negative.')

    # begin calculating parameters

    # find center point
    if center == 'pot' :
        center = charm.findAttributeMin(group, 'potential')
    else:
        center = charm.getCenterOfMass(center)
    
    # get center_vel and center_angular_mom
    # families must be parsed individually then combined
    vmdata = charm.reduceParticle(famgroups[0], vmmap, vmreduce, None)
    if vmdata == None :
        raise StandardError('MapReduce returned NoneType object.')
    center_vel = vmdata[0][2]
    center_angular_mom = vmdata[0][3]
    # if there are additional families, parse each then combine results weighting by mass
    if len(famgroups) > 1 :
        old_mass = vmdata[0][1]
        for i in range(len(famgroups)-1) :
            vmdata = charm.reduceParticle(famgroups[i+1], vmmap, vmreduce, None)
            new_mass = vmdata[0][1]
            center_vel = weightvecs(old_mass, center_vel, new_mass, vmdata[0][2])
            center_angular_mom = weightvecs(old_mass, center_angular_mom, new_mass, vmdata[0][3])
            old_mass += new_mass
    
    # for an elliptical projection, use Katz to get shape & then find vel, mom
    # when restoring this, find out what happened to center_ell?
    if projection == 'ell' :
        if fit_radius == 0. :
            print 'fit_radius = 0 in an elliptical projection.\nusing all particles in batch to find shape of ellipses.'
        ell_matrix = [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]
        center_ell = [0., 0., 0.]
        ba = ca = phi = theta = psi = 0.
        center = list(center)
        shape_data = elliptical.find_shape(famgroups, center, fit_radius, ell_matrix, center_ell)
        center = tuple(center)
        if type(shape_data) == type(None) :
            print 'find_shape() did not succeed'
            return
            # raise StandardError('Problem in elliptical.find_shape(): no fit found.')
        else :
            ba, ca, phi, theta, psi = shape_data
            print 'b/a = %g, c/a = %g' % (ba, ca)
        center = [0.]*config.MAXDIM
        center_vel = [0.]*config.MAXDIM
        center_angular_mom = [0.]*config.MAXDIM
        vel_data = elliptical.find_vel(famgroups,center,center_vel,center_angular_mom, ell_matrix, center_ell, ba, ca, fit_radius)
    else :
        ba, ca, phi, theta, psi, center_ell, ell_matrix = (0., 0., 0., 0., 0., [0.]*config.MAXDIM, [[0.]*config.MAXDIM]*config.MAXDIM)

    # find max_radius
    # maxradmap iterates over all particles and compares each radius to the previous max found
    p_param = (center)
    max_radius = 0.
    if family == 'all' :
        max_radius = charm.reduceParticle(group, maxradmap, maxradreduce, p_param)[0][1]
    else :
        for i in range(len(famgroups)) :
            fam_radius = charm.reduceParticle(famgroups[i], maxradmap, maxradreduce, p_param)[0][1]
            max_radius = max(max_radius, fam_radius)
    
    # TIPSY uses an approximation for max_radius which can't be adequately emulated here.
    # for the run99 data file, the value of max_radius is 8.18829; set it manually.
    # max_radius = 8.18829
    
    # determine bin_size
    # if min_radius > 0, then bin 0 should have the specified radius.
    # other than this exception, all bins have constant size in either lin or log space as specified
    if min_radius > max_radius and nbins > 1 :
        raise StandardException('Value for min_radius encompasses all particles; cannot bin data.')
    # min_radius > 0 case creates a scenario where nbins = 1 would create a /0 error, must handle here.
    if nbins == 1 :
        bin_size = max_radius
        # bin_type and min_radius are superfluous to nbins = 1 case
        bin_type = 'lin'
        min_radius = 0.
    # find size in lin space
    elif bin_type == 'lin' :
        if min_radius > 0. :
            bin_size = (max_radius - min_radius) / float(nbins - 1)
        else :
            bin_size = (max_radius - min_radius) / float(nbins)
    # find size in log space
    else :
        min_radius = math.log10(min_radius)
        bin_size = (math.log10(max_radius) - min_radius) / float(nbins - 1)
    
    # calculate bin boundary radii
    bounds = [0.] * (nbins + 1)
    # the first boundary radius is affected by min_radius, handle
    if bin_type == 'lin' and min_radius == 0.:
        bounds[1] = bin_size
    else :
        bounds[1] = min_radius
    # each following bound should be bound[previous] + bin_size
    for i in range(2, nbins + 1) :
        bounds[i] = bounds[i - 1] + bin_size
    # if logarithmic binning, convert values into linear space
    if bin_type == 'log' :
        for i in range(1, nbins + 1) :
            bounds[i] = pow(10., bounds[i])

    starlf = star_lum.star_lum()
    
    sim_time = charm.getTime()
    
    # do calculations which must see individual particles.
    # the set of attributes on a particle varies by family, so each family must be processed seperately
    params = [None, isbaryon, bounds, projection, nbins, bin_type, bin_size, min_radius, max_radius, center, center_vel, ell_matrix, center_ell, ba, ca, config.msolunit, config.gasconst, sim_time, config.time_unit, starlf.age, starlf.lum, starlf.lumv_fit, starlf.vv_dat, starlf.vv_fit, starlf.bv_dat, starlf.bv_fit, center_angular_mom]
    fam_data = [None] * len(famgroups)
    for i in range(len(famgroups)) :
        params[0] = families[i]
        fam_data[i] = charm.reduceParticle(famgroups[i], basemap, basereduce, tuple(params))
        
    # shows per-family result of MapReduce, sometimes useful for debugging
    #    if debug_flag == 1 :
    #        print '\nThe current family is: ' + families[i]
    #        for line in fam_data[i] :
    #            print line
    if len(fam_data) < 1 or fam_data == None :
        raise StandardException('MapReduce for fam_data has length zero or is NoneType.')
    
    # sum results into one list.
    # Note that if a bin has no particles, it will be missing from the reduce result. data[] should have no missing rows.
    # values are: bin, number, mass, vel_radial, vel_radial_sigma, vel_tang_sigma, angular_mom[x,y,z], lum, density, temp, pressure, entropy, gas_mass
    data = [None] * nbins
    for i in range(nbins) :
        data[i] = [i, 0, 0., 0., 0., 0., [0., 0., 0.], 0., 0., 0., 0., 0., 0.]    
    for fam in fam_data :
        for row in fam :
            bin = row[0]
            # merge fields 0 thru 5
            for i in range(1, 6) :
                data[bin][i] += row[i]
            # merge field 6 (angular momentum vector)
            for i in range(3) :
                data[bin][6][i] += row[6][i]
            # merge fields 7 thru 12
            for i in range(7, 13) :
                data[bin][i] += row[i]
    if not len(data) == nbins :
        raise StandardError('nbins != length of result after basemap')

    # calculate remaining "base" values that did not need to be handled in the map
    mass_r = 0.
    for i in range(nbins) :
        # get max radius, min radius, and mean radius
        r_max = bounds[i + 1]
        r_min = bounds[i]
        r_mean = (r_max + r_min) / 2.
        # number of particles in bin
        number = data[i][1]
        # if the bin is empty then some calculations e.g. 1/mass will explode; catch these.
        if number != 0 :
            # find volume by projection
            pi = 3.141592653589793
            if projection == 'ell' :
                volume = 4. * ba * ca / 3. * pi * (pow((r_max),3) - pow((r_min),3))
            elif projection == 'cyl' :
                volume = pi * (pow((r_max),2) - pow((r_min),2))
            else :
                volume = (4. / 3.) * pi * (pow(r_max,3) - pow(r_min,3))
            # unpack values. deal with non-sum calculations, largely n / mass
            mass = data[i][2]
            mass_r += mass
            vel_radial = data[i][3] / mass
            vel_radial_sigma = data[i][4] / mass
            if vel_radial_sigma > vel_radial**2 :
                vel_radial_sigma = math.sqrt(vel_radial_sigma - vel_radial**2)
            else :
                vel_radial_sigma = 0.
            vel_tang_sigma = data[i][5] / mass
            ang_mom = scalevec(1./mass, data[i][6])
            ang = vlength(ang_mom)
            if ang > 0.0 :
                ang_theta = 180.0 * math.acos(ang_mom[2] / ang) / pi
            else :
                ang_theta = 0.0
            ang_phi = 180.0 * math.atan2(ang_mom[1], ang_mom[0]) / pi
            rho = mass / volume
            vel_circ = ang / r_mean
            c_vel = math.sqrt(mass_r / r_max)
            if vel_tang_sigma > vel_circ**2 :
                vel_tang_sigma = math.sqrt(vel_tang_sigma - vel_circ**2)
            else :
                vel_tang_sigma = 0.
            # star stuff
            lum_den = data[i][7] / volume
            # gas stuff
            if 'gas' in families and data[i][12] > 0 :
                density  = data[i][8]  / data[i][12]
                temp     = data[i][9]  / data[i][12]
                pressure = data[i][10] / data[i][12]
                entropy  = data[i][11] / data[i][12]
            else :
                density  = 0.
                temp     = 0.
                pressure = 0.
                entropy  = -config.HUGE
            data[i] = [r_max, number, rho, mass_r, c_vel, vel_radial, vel_radial_sigma, vel_circ, vel_tang_sigma, ang, ang_theta, ang_phi, density, temp, pressure, entropy, lum_den]
        else :
            c_vel = math.sqrt(mass_r / r_max)
            data[i] = [r_max, 0, 0., mass_r, c_vel, 0., 0., 0., 0., 0., 0.,
                       0., 0., 0., 0., 0., 0.]
    
    # build header row
    # may need to update the exact text used for clarity or for consistency with TIPSY
    headers = ('radius', 'number', 'rho', 'mass_r', 'c_vel', 'vel_radial', 'vel_radial_sigma', 'vel_circ', 'vel_tang_sigma', 'ang', 'ang_theta', 'ang_phi')
    if family in ['gas', 'baryon', 'all'] :
        headers += ('mmwg_density', 'mwg_temp', 'mwg_pres', 'mwg_entr')
    if family in ['star', 'baryon', 'all'] :
        headers += ('lum_V',)
    
    # write output to file
    f = open(filename, 'w')
    # write headers according to families present
    f.write('#')
    for i in range(len(headers)) :
        f.write(' ' + headers[i])
    f.write('\n')
    # write data according to families present
    for i in range(nbins) :
        f.write('%g %d %g %g %g %g %g %g %g %g %g %g' % tuple(data[i][0:12]))
        if 'gas' in families :
            f.write(' %g %g %g %g' % tuple(data[i][12:16]))
        if 'star' in families :
            f.write(' %g' % tuple(data[i][16:17]))
        f.write('\n')
    f.close()

    # there is no current mechanism to delete groups.
    # if one is added, delete temporary working groups here.
  except :
    print traceback.format_exc()
예제 #8
0
def writeBoxAscii(boxRadius, filename, angMomGroup=None, centerMethod ='pot'):
    """Writes out an tipsy-ascii (filename) representation for a box aligned with the galactic coordinate system spanning +-boxRadius (given in kpc) in the galcoord directions. center can be 'pot' or 'com'.  Default angMomGroup is cold galactic gas."""
    if (angMomGroup==None):
        angMomGroup = 'angMomGroup'
        center = findcenter.findCenter(method=centerMethod)
        virialRadius = virialgroup.getVirialGroup()
        charm.createGroupAttributeSphere('angMomGroup', 'All', 'position', center[0], center[1], center[2], virialRadius*quesoConfig.rgalFraction)
        charm.createGroup_Family('angMomGroup', 'angMomGroup', 'gas')
        charm.createGroup_AttributeRange('angMomGroup', 'angMomGroup', 'temperature', 0, quesoConfig.coldGasTemp)
    else: 
        center = findcenter.findCenter(group2=angMomGroup,method=center)
        
    boxRad1 = boxRadius/(charm.getTime()*quesoConfig.kpcunit)
    print 'here'
    galcoord.calcGalacticCoordinates(angMomGroup=angMomGroup, center=centerMethod)
    galZ = vectormath.normalizeVector(angmom.getAngMomVector(angMomGroup))
    galX = vectormath.normalizeVector(vectormath.crossVectors((0,1,0),galZ))
    galY = vectormath.normalizeVector(vectormath.crossVectors(galZ,galX))
    #===========================================================================
    # Create the cube
    #===========================================================================
    cornerVec = vectormath.addVectors(vectormath.multVectorScalar(boxRad1, galX),vectormath.multVectorScalar(boxRad1, galY))
    cornerVec = vectormath.addVectors(cornerVec,vectormath.multVectorScalar(boxRad1, galZ))
    cornerVec = vectormath.subVectors(center, cornerVec)
    edge1 = vectormath.multVectorScalar(2*boxRad1,galX)
    edge2 = vectormath.multVectorScalar(2*boxRad1,galY)
    edge3 = vectormath.multVectorScalar(2*boxRad1,galZ)
    charm.createGroupAttributeBox('galBox', 'All', 'position',
                                  cornerVec[0],cornerVec[1],cornerVec[2],
                                  edge1[0]    ,edge1[1]    ,edge1[2],
                                  edge2[0]    ,edge2[1]    ,edge2[2],
                                  edge3[0]    ,edge3[1]    ,edge3[2])
    numStars = charm.getNumParticles('galBox','star')
    numGas   = charm.getNumParticles('galBox','gas')
    numDark  = charm.getNumParticles('galBox','dark')
    numTotal = numStars + numGas + numDark
    #===========================================================================
    # This region outputs the ascii file to be read in by tipsy
    #===========================================================================
    f = open(filename, 'w') # overwrites pre-existing file
    f.write(str(numTotal) + ' ' + str(numGas) + ' ' + str(numStars))
    f.write('\n3')
    f.write('\n'+ str(charm.getTime())+ '\n')
    f.close()
    for each in ['star','dark','gas']:charm.createScalarAttribute(each, 'tmpWorking')
    def writeAndAppend(attribute):
        charm.writeGroupArray('tmpGalBox', attribute, '/tmp/out.tmp')
        os.system('tail -n +2 /tmp/out.tmp >> ' + filename)
        return
    families = ['gas','dark','star']
    for each in families:
        charm.createGroup_Family('tmpGalBox', 'galBox', each)
        writeAndAppend('mass')
    # Positions
    for i in range(0,3):
        for each in families:
            charm.createGroup_Family('tmpGalBox', 'galBox', each)
            charm.runLocalParticleCodeGroup('tmpGalBox', vectorWriter, ('pos', i))
            writeAndAppend('tmpWorking')
    # Velocities
    for i in range(0,3):
        for each in families:
            charm.createGroup_Family('tmpGalBox', 'galBox', each)
            charm.runLocalParticleCodeGroup('tmpGalBox', vectorWriter, ('vel', i))
            writeAndAppend('tmpWorking')
    # Star and dark softening
    for each in ['dark', 'star']:
        charm.createGroup_Family('tmpGalBox', 'galBox', each)
        writeAndAppend('softening')        
    # Gas attributes
    charm.createGroup_Family('tmpGalBox', 'galBox', 'gas')
    for each in ['density','temperature','softening','metals']:
        writeAndAppend(each)
    #Star stuff
    charm.createGroup_Family('tmpGalBox', 'galBox', 'star')
    for each in ['metals','formationtime']:
        writeAndAppend(each)
    #potential
    for each in families:
        charm.createGroup_Family('tmpGalBox', 'galBox', each)
        writeAndAppend('potential')
    charm.deleteGroup('tmpGalBox')
    #print 'num lines in ' + filename + ' should be: ' + str(9*numTotal+3*numGas+2*numStars+3)
    return