def getFamilyAttributeSum(center2,r,family,attribute): """Integrates attributes of a given family over a given sphere.""" charm.createGroupAttributeSphere('group', 'All', 'position', center2[0], center2[1], center2[2], r) charm.createGroup_Family('group','group',family) sum = charm.getAttributeSum('group', family, attribute) charm.deleteGroup('group') return sum
def getGalDensity(center2, r): charm.createGroupAttributeSphere(virialGroup, "All", "position", center[0], center[1], center[2], r) totMass = 0.0 for fam in charm.getFamilies(): totMass += charm.getAttributeSum(virialGroup, fam, "mass") v = (4 * math.pi / 3.0) * r ** 3 density = totMass / v return density
def getNormalStarAngMom(center2, radius, comVel=None): """Calculates the stellar angular momentum vector given a center and radius. By default the COM velocity is calculated unless it is passed.""" if (comVel==None):vCM=getVelCMStars(center2, radius) else: vCM = comVel charm.createGroupAttributeSphere('groupAll', 'All', 'position', center2[0], center2[1], center2[2], radius) charm.createGroup_Family('groupStar', 'groupAll', 'star') starAngMom1 = charm.reduceParticle('groupStar', getParticleAngMomentum, sumAngMomentum, [center2,vCM]) starAngMom = (starAngMom1[0][1],starAngMom1[0][2],starAngMom1[0][3]) starAngMomMag = math.sqrt(starAngMom[0]**2+starAngMom[1]**2+starAngMom[2]**2) starAngMom = (starAngMom[0]/starAngMomMag,starAngMom[1]/starAngMomMag,starAngMom[2]/starAngMomMag) return starAngMom
def setsphere(group, *args) : """Select particles within radius from coordinate.""" import charm try : # parse args if len(args) < 3 : raise TypeError('Too few arguments') if type(args[0]) == str : if args[0] == 'pot' or args[0] == 'potential ': center = charm.findAttributeMin(args[1], 'potential') radius = args[2] if(len(args) == 4) : parent = args[3] else : parent = 'All' elif args[0] == 'com' : if type(args[1]) != str : raise StandardError('third argument should be a group') if args[2] == 'all' or args[2] == 'All' : center = charm.getCenterOfMass(args[1]) radius = args[3] if(len(args) == 5) : parent = args[4] else : parent = 'All' elif args[2] == 'gas' : charm.createGroup_Family("__tmpgroup", args[1], 'gas') center = charm.getCenterOfMass(args[1]) radius = args[3] if(len(args) == 5) : parent = args[4] else : parent = 'All' elif args[2] == 'dark' : charm.createGroup_Family("__tmpgroup", args[1], 'dark') center = charm.getCenterOfMass(args[1]) radius = args[3] if(len(args) == 5) : parent = args[4] else : parent = 'All' elif args[2] == 'star' : charm.createGroup_Family("__tmpgroup", args[1], 'star') center = charm.getCenterOfMass(args[1]) radius = args[3] if(len(args) == 5) : parent = args[4] else : parent = 'All' else : raise StandardError('unknown particle type: ' + args[2]) else : raise StandardError('unknown center type: ' + args[0]) else : center = (args[0], args[1], args[2]) radius = args[3] if(len(args) == 5) : parent = args[4] else : parent = 'All' # check if simulation loaded if charm.getGroups() == None : raise StandardError('Simulation not loaded') charm.createGroupAttributeSphere(group, parent, 'position', center[0], center[1], center[2], radius) except : print traceback.format_exc()
def findCenter(group2='All', method = 'pot' ): """Finds the center of a given group based on method as 'com' or 'pot'""" if (method=='pot'): if (group2=='All'): charm.createGroup_AttributeRange('highres', 'All', 'mass', -1, 7e-12) cntHr = charm.getCenterOfMass('highres') charm.createGroupAttributeSphere('centerhr', 'All', 'position', cntHr[0], cntHr[1], cntHr[2], 1000./136986.30137) cnt = charm.findAttributeMin('centerhr', 'potential') else: cnt = charm.findAttributeMin(group2, 'potential') elif (method=='com'): cnt = charm.getCenterOfMass(group2) return cnt
def getVelCMStars(center2, radius): "Returns the vector for the center of mass velocity of a group of stars defined by center2 coordinates and a radius." charm.createGroupAttributeSphere('tmpGal', 'All', 'position', center2[0], center2[1], center2[2], radius) #use cmVelCompare2.py to choose length charm.createGroup_Family('tmpStarGroup', 'tmpGal', 'star') #select star particles only massStar = charm.getAttributeSum('tmpGal', 'star', 'mass') mass = massStar #calculate total mass vmomentStar = charm.reduceParticle('tmpStarGroup', centMassVelMap, centMassReduce, None) vmoment = [vmomentStar[0][1],vmomentStar[0][2],vmomentStar[0][3]] vcm = (vmoment[0]/mass, vmoment[1]/mass, vmoment[2]/mass) #Clean up charm.deleteGroup('tmpGal') charm.deleteGroup('tmpStarGroup') return vcm #return the COM velocity vector
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
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
def getSFRTimeProfile(nbins=500): """Returns the list of tuples (time, SFR) in solar masses/year! (for the 0.5Gyr preceding each time)""" #read in initial masses from file filename = quesoConfig.dataDir + quesoConfig.preTimestepFilename + quesoConfig.nTimesteps + ".massform" charm.readTipsyArray(filename,'initialMass') simTime = getSimTime()/quesoConfig.timeunit #time in simulation units profileTStep = simTime/nbins sfr = [(0,0)]*nbins center = findcenter.findCenter() rgal = virialgroup.getVirialGroup()*quesoConfig.rgalFraction charm.createGroupAttributeSphere('galStar', 'star', 'position', center[0], center[1], center[2], rgal) #Particles within galactic radius charm.createGroup_Family('galStar', 'galStar', 'star') param = (profileTStep, nbins) reduceResult = charm.reduceParticle('galStar' , mapSFR, reduceSFR, param) #sum = 0.0 for i in range(0,len(reduceResult)): #try: formationRate = reduceResult[i][1]*quesoConfig.msolunit/(profileTStep*quesoConfig.timeunit) #msolar/yr age = (simTime -reduceResult[i][0]*profileTStep)*quesoConfig.timeunit/1e9 #in gyr sfr[reduceResult[i][0]-1] =(age, formationRate) return sfr
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)
def getVirialGroup(group="All", center2="pot", virialGroup="virialGroup"): """This method returns the virial radius of a given group, bases around a center that can be given by one of three options: Default 'pot' finds the potential minimum, 'com' uses the center of mass, or a tuple of length 3 can be given. virialGroup specifies the group name of the resulting """ global center if center2 == "pot": cnt = findcenter.findCenter(group2=group, method="pot") elif center2 == "com": cnt = findcenter.findCenter(group2=group, method="com") elif len(center2) == 3: cnt = center2 center = cnt # use center variable at later times. # =========================================================================== # Use center coordinates to find virial radius and return group # Returns virial radius in sim units via bisection method. # If this doesn't converge, try larger bounds or adjust the # other parameters in source. # =========================================================================== def getGalDensity(center2, r): charm.createGroupAttributeSphere(virialGroup, "All", "position", center[0], center[1], center[2], r) totMass = 0.0 for fam in charm.getFamilies(): totMass += charm.getAttributeSum(virialGroup, fam, "mass") v = (4 * math.pi / 3.0) * r ** 3 density = totMass / v return density # ================================================================ # Specify bounds of bisection. Default is 0.1 to 400kpc (at redshift zero) epsilon = 0.001 # maximum error in density convergence count = 0 maxIterations = 200 leftr = 0.1 / quesoConfig.kpcunit rightr = 4000.0 / quesoConfig.kpcunit # ================================================================ from queso.quesoConfig import virialRadiusDensity midpoint = (leftr + rightr) / 2 leftDensity = getGalDensity(center, leftr) - virialRadiusDensity # Initialize values rightDensity = getGalDensity(center, rightr) - virialRadiusDensity # offset so we can find root midDensity = getGalDensity(center, midpoint) - virialRadiusDensity # offset so we can find root # Bisection to find virial radius as defined in quesoConfig # Run until values converge within epsilon or reach max count while (count < maxIterations) & (math.fabs(leftDensity - rightDensity) > epsilon): midpoint = (leftr + rightr) / 2 leftDensity = getGalDensity(center, leftr) - virialRadiusDensity # offset so we can find root rightDensity = getGalDensity(center, rightr) - virialRadiusDensity # offset so we can find root midDensity = getGalDensity(center, midpoint) - virialRadiusDensity # offset so we can find root if leftDensity * midDensity < 0: rightr = midpoint elif rightDensity * midDensity < 0: leftr = midpoint elif midDensity == 0: break elif (leftDensity * midDensity > 0) & (rightDensity * midDensity > 0): print "\nVirial radius calculation 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 charm.createGroupAttributeSphere(virialGroup, "All", "position", center[0], center[1], center[2], midpoint) return midpoint # in sim units
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