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 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 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
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
def getAngMomVector(group, center='pot'): """Returns specific angular momentum vectors in physical units. Center can be 'pot' or 'com'""" if ((group in charm.getGroups())==False): print "Group does not exist, please try again." return def multVectorScalar(scalar,vector): return (vector[0]*scalar,vector[1]*scalar,vector[2]*scalar) center = findcenter.findCenter(group2=group,method=center) #find COM Velocity vCM=getVelCM(group) angMomVector = charm.reduceParticle(group, getParticleAngMomentum, sumAngMomentum, [center,vCM]) mass = charm.getAttributeSum(group, 'gas', 'mass') mass += charm.getAttributeSum(group, 'star', 'mass') mass += charm.getAttributeSum(group, 'dark', 'mass') unitConvert = quesoConfig.kpcunit*quesoConfig.velocityunit #masses are divided out anyway. #Convert this into a specific angular momentum 3-vector angMomVector = multVectorScalar(unitConvert/mass, (angMomVector[0][1] ,angMomVector[0][2] ,angMomVector[0][3])) return angMomVector
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