def writemark(group, filename) : """Write a file which contains the index values for all particles in a group. This file is typically used to export and import particle markings. The file has a header row with ntotal ngas nstar.""" import charm # check if simulation loaded groups = charm.getGroups() if groups == None : raise StandardError('Simulation not loaded') # check if group exists if group not in groups : raise StandardError('Group ' + group + ' does not exist') ngas = charm.getNumParticles(group, 'gas') nstar = charm.getNumParticles(group, 'star') ntotal = ngas + nstar + charm.getNumParticles(group, 'dark') # record header row to file f = open(filename, 'w') f.write('%d %d %d\n' % (ntotal, ngas, nstar)) f.close() # record index values charm.writeIndexes(group, 'gas', filename) charm.writeIndexes(group, 'dark', filename) charm.writeIndexes(group, 'star', filename)
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
def metalProfile(group, nbins=20, center="pot", family="bar"): if (group in charm.getGroups()) == False: print "Group does not exist, please try again." return if (family in ["star", "bar", "gas"]) == False: print 'Invalid family. Need "bar","gas", or "star"' return center = findcenter.findCenter(group2=group, method=center) radialStep = getgroupradius.getGroupRadius(group, center) / nbins metalRad = [0] * (nbins) metalProf = [0] * (nbins) numStar = charm.getNumParticles(group, "star") numGas = charm.getNumParticles(group, "gas") if (numGas == 0) & (numStar == 0): return metalProf if (numStar != 0) & (family == "star"): charm.createGroup_Family("groupMetStar", group, "star") metalStar = charm.reduceParticle("groupMetStar", massMetal, reduceMassMetal, (radialStep, center)) for i in range(len(metalStar)): metalProf[metalStar[i][0]] = metalStar[i][1] / metalStar[i][2] if (numGas != 0) & (family == "gas"): charm.createGroup_Family("groupMetGas", group, "gas") metalGas = charm.reduceParticle("groupMetGas", massMetal, reduceMassMetal, (radialStep, center)) for i in range(len(metalGas)): metalProf[metalGas[i][0]] = metalGas[i][1] / metalGas[i][2] if family == "bar": charm.createGroup_Family("groupMetGas", group, "gas") charm.createGroup_Family("groupMetStar", group, "star") metalProfGas = [[0, 0]] * nbins metalProfStar = [[0, 0]] * nbins metalGas = charm.reduceParticle("groupMetGas", massMetal, reduceMassMetal, (radialStep, center)) for i in range(len(metalGas)): metalProfGas[metalGas[i][0]][0] = metalGas[i][1] metalProfGas[metalGas[i][0]][1] = metalGas[i][2] metalStar = charm.reduceParticle("groupMetStar", massMetal, reduceMassMetal, (radialStep, center)) for i in range(len(metalStar)): metalProfStar[metalStar[i][0]][0] = metalStar[i][1] metalProfStar[metalStar[i][0]][1] = metalStar[i][2] for i in range(len(metalProf)): metalTot = metalProfStar[i][0] + metalProfGas[i][0] massTot = metalProfStar[i][1] + metalProfGas[i][1] if massTot != 0: metalProf[i] = metalTot / massTot for i in range(nbins): metalRad[i] = (i + 0.5) * radialStep return (metalRad, metalProf)
def getMeanMetals(group , family='bar'): if ((group in charm.getGroups())==False): print "Group does not exist, please try again." return metalStar = [(0,0,0)] metalGas = [(0,0,0)] numStar = charm.getNumParticles(group, 'star') numGas = charm.getNumParticles(group, 'gas') if (numStar !=0) & (family=='bar' or family=='star'): charm.createGroup_Family('groupMetStar',group, 'star') metalStar = charm.reduceParticle('groupMetStar',massMetal,reduceMassMetal,None) if (numGas !=0) & (family=='bar' or family=='gas'): charm.createGroup_Family('groupMetGas',group , 'gas') metalGas = charm.reduceParticle('groupMetGas' ,massMetal,reduceMassMetal,None) if (numGas==0) & (numStar==0): return 0 metals = (metalStar[0][1] + metalGas[0][1])/(metalStar[0][2]+metalGas[0][2]) return metals
def boxstat(group, family='all') : """Print statistics for a group as in the tipsy boxstat command Arguments are group and family Return physical parameters of particles: number, mass, center of box, size of box, center of mass, center of mass's velocity, angular momentum vector. Format output to say if gas, dark, star, baryon, or all. Check error cases: Bad input, Not a proper data type, Box not loaded.""" import charm # check if simulation loaded if charm.getGroups() == None : raise StandardError('Simulation not loaded') # There is a potential issue with the capitalization of "all" being mixed # in different implementations. Take either. if family == 'All': family = 'all' if group == 'all': group = 'All' # Prepare values based on selected family if family == 'all': nPartGas = charm.getNumParticles(group, 'gas') nPartDark = charm.getNumParticles(group, 'dark') nPartStar = charm.getNumParticles(group, 'star') mass = charm.getAttributeSum(group, 'gas', 'mass') mass += charm.getAttributeSum(group, 'dark', 'mass') mass += charm.getAttributeSum(group, 'star', 'mass') bBox = list(charm.getAttributeRangeGroup(group, 'gas', 'position')) bBoxTmp = charm.getAttributeRangeGroup(group, 'dark', 'position') bBox[0] = map(lambda x, y : min(x,y), bBox[0], bBoxTmp[0]) bBox[1] = map(lambda x, y : max(x,y), bBox[1], bBoxTmp[1]) bBoxTmp = charm.getAttributeRangeGroup(group, 'star', 'position') bBox[0] = map(lambda x, y : min(x,y), bBox[0], bBoxTmp[0]) bBox[1] = map(lambda x, y : max(x,y), bBox[1], bBoxTmp[1]) groupfamname = group elif family == 'baryon': nPartGas = charm.getNumParticles(group, 'gas') nPartStar = charm.getNumParticles(group, 'star') mass = charm.getAttributeSum(group, 'gas', 'mass') mass += charm.getAttributeSum(group, 'star', 'mass') bBox = list(charm.getAttributeRangeGroup(group, 'gas', 'position')) bBoxTmp = charm.getAttributeRangeGroup(group, 'star', 'position') bBox[0] = map(lambda x, y : min(x,y), bBox[0], bBoxTmp[0]) bBox[1] = map(lambda x, y : max(x,y), bBox[1], bBoxTmp[1]) groupfamname = group else : nPart = charm.getNumParticles(group, family) mass = charm.getAttributeSum(group, family, 'mass') bBox = charm.getAttributeRangeGroup(group, family, 'position') groupfamname = group + 'FAM' + family charm.createGroup_Family(groupfamname, group, family) # Derive box properties size = map(lambda min, max : max - min, bBox[0], bBox[1]) center = map(lambda min, max : 0.5*(max + min), bBox[1], bBox[0]) mmoment = charm.reduceParticle(groupfamname, centmassmap, centmassreduce, None) cm = [mmoment[0][1]/mass, mmoment[0][2]/mass, mmoment[0][3]/mass] vmoment = charm.reduceParticle(groupfamname, centmassVelmap, centmassreduce, None) vcm = [vmoment[0][1]/mass, vmoment[0][2]/mass, vmoment[0][3]/mass] angmom1 = charm.reduceParticle(groupfamname, angmomMap, centmassreduce, None) # Apply parallel axis theorem and make specific angmom = [0,0,0] angmom[0] = (angmom1[0][1] - mass*(cm[1]*vcm[2] - cm[2]*vcm[1]))/mass angmom[1] = (angmom1[0][2] - mass*(cm[2]*vcm[0] - cm[0]*vcm[2]))/mass angmom[2] = (angmom1[0][3] - mass*(cm[0]*vcm[1] - cm[1]*vcm[0]))/mass # Write output header according to type of particles if family == 'all' : print 'number of dark, gas and star particles =', nPartDark, nPartGas, nPartStar elif family == 'baryon' : print 'number of baryon particles =', (nPartGas + nPartStar) else: print 'number of', family, 'particles =', nPart # Write physical parameters print 'mass =', mass print 'center coordinates =', center print 'size =', size print 'center of mass coordinates =', cm print 'center of mass velocity =', vcm print 'angular momentum vector =', angmom
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()
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