def v_xy(f, param, changbin=None, nr=50, min_per_bin=100): """ Attempts to calculate the circular velocities for particles in a thin (not flat) keplerian disk. Requires ChaNGa **ARGUMENTS** f : tipsy snapshot For a gaseous disk param : dict a dictionary containing params for changa. (see isaac.configparser) changbin : str (OPTIONAL) If set, should be the full path to the ChaNGa executable. If None, an attempt to find ChaNGa is made nr : int (optional) number of radial bins to use when averaging over accelerations min_per_bin : int (optional) The minimum number of particles to be in each bin. If there are too few particles in a bin, it is merged with an adjacent bin. Thus, actual number of radial bins may be less than nr. **RETURNS** vel : SimArray An N by 3 SimArray of gas particle velocities. """ if changbin is None: # Try to find the ChaNGa binary full path changbin = os.popen('which ChaNGa_uw_mpi').read().strip() # Load up mpi # Load stuff from the snapshot x = f.g['x'] y = f.g['y'] z = f.g['z'] r = f.g['rxy'] vel0 = f.g['vel'].copy() # Remove units from all quantities r = isaac.strip_units(r) x = isaac.strip_units(x) y = isaac.strip_units(y) z = isaac.strip_units(z) # Temporary filenames for running ChaNGa f_prefix = str(np.random.randint(0, 2**32)) f_name = f_prefix + '.std' p_name = f_prefix + '.param' # Update parameters p_temp = param.copy() p_temp['achInFile'] = f_name p_temp['achOutName'] = f_prefix if 'dDumpFrameTime' in p_temp: p_temp.pop('dDumpFrameTime') if 'dDumpFrameStep' in p_temp: p_temp.pop('dDumpFrameStep') # -------------------------------------------- # Estimate velocity from gravity only # -------------------------------------------- # Note, accelerations due to gravity are calculated twice to be extra careful # This is so that any velocity dependent effects are properly accounted for # (although, ideally, there should be none) # The second calculation uses the updated velocities from the first for iGrav in range(2): # Save files f.write(filename=f_name, fmt = pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, only calculating gravity command = 'mpirun --mca mtl mx --mca pml cm ' + changbin + ' -gas -n 0 ' + p_name #command = 'charmrun ++local ' + changbin + ' -gas -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a = isaac.load_acc(acc_name) # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # If a is not a vector, calculate radial acceleration. Otherwise, assume # a is the radial acceleration a_r = a[:,0]*x/r + a[:,1]*y/r # Make sure the units are correct then remove them a_r = isaac.match_units(a_r, a)[0] a_r = isaac.strip_units(a_r) # Calculate cos(theta) where theta is angle above x-y plane cos = r/np.sqrt(r**2 + z**2) ar2 = a_r*r**2 # Bin the data r_edges = np.linspace(r.min(), (1+np.spacing(2))*r.max(), nr + 1) ind, r_edges = isaac.digitize_threshold(r, min_per_bin, r_edges) ind -= 1 nr = len(r_edges) - 1 r_bins, ar2_mean, err = isaac.binned_mean(r, ar2, binedges=r_edges, \ weighted_bins=True) # Fit lines to ar2 vs cos for each radial bin m = np.zeros(nr) b = np.zeros(nr) for i in range(nr): mask = (ind == i) p = np.polyfit(cos[mask], ar2[mask], 1) m[i] = p[0] b[i] = p[1] # Interpolate the line fits m_spline = isaac.extrap1d(r_bins, m) b_spline = isaac.extrap1d(r_bins, b) # Calculate circular velocity ar2_calc = m_spline(r)*cos + b_spline(r) v_calc = np.sqrt(abs(ar2_calc)/r) vel = f.g['vel'].copy() v_calc = isaac.match_units(v_calc,vel)[0] vel[:,0] = -v_calc*y/r vel[:,1] = v_calc*x/r # Assign to f f.g['vel'] = vel # -------------------------------------------- # Estimate pressure/gas dynamics accelerations # -------------------------------------------- a_grav = a ar2_calc_grav = ar2_calc # Save files f.write(filename=f_name, fmt = pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, including SPH command = 'mpirun --mca mtl mx --mca pml cm ' + changbin + ' +gas -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a_total = isaac.load_acc(acc_name) # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Estimate the accelerations due to pressure gradients/gas dynamics a_gas = a_total - a_grav ar_gas = a_gas[:,0]*x/r + a_gas[:,1]*y/r ar_gas = isaac.strip_units(ar_gas) ar2_gas = ar_gas*r**2 logr_bins, ratio, err = isaac.binned_mean(np.log(r), ar2_gas/ar2_calc_grav, nbins=nr,\ weighted_bins=True) r_bins = np.exp(logr_bins) ratio_spline = isaac.extrap1d(r_bins, ratio) ar2_calc = ar2_calc_grav*(1 + ratio_spline(r)) a_calc = ar2_calc/r**2 v = np.sqrt(r*abs(a_calc)) v = isaac.match_units(v, vel0.units)[0] vel = vel0.copy() vel[:,0] = -v*y/r vel[:,1] = v*x/r # more cleanup f.g['vel'] = vel0 return vel
def v_xy(f, param, changbin=None, nr=50, min_per_bin=100, changa_preset=None, \ max_particles=None, est_eps=True): """ Attempts to calculate the circular velocities for particles in a thin (not flat) keplerian disk. Also estimates gravitational softening (eps) for the gas particles Requires ChaNGa Note that this will change the velocities IN f **ARGUMENTS** f : tipsy snapshot For a gaseous disk param : dict a dictionary containing params for changa. (see isaac.configparser) changbin : str (OPTIONAL) If set, should be the full path to the ChaNGa executable. If None, an attempt to find ChaNGa is made nr : int (optional) number of radial bins to use when averaging over accelerations min_per_bin : int (optional) The minimum number of particles to be in each bin. If there are too few particles in a bin, it is merged with an adjacent bin. Thus, actual number of radial bins may be less than nr. changa_preset : str Which ChaNGa execution preset to use (ie 'mpi', 'local', ...). See ICgen_utils.changa_command max_particles : int or None Specifies the maximum number of particles to use for calculating accelerations and velocities. Setting a smaller number can speed up computation and save on memory but can yield noisier results. If None, max is unlimited. est_eps : bool Estimate eps (gravitational softening length). Default is True. If False, it is assumed eps has already been estimated **RETURNS** Nothing. Velocities are updated within f as is eps """ # If the snapshot has too many particles, randomly select gas particles # To use for calculating velocity and make a view of the snapshot n_gas = len(f) - 1 subview = (n_gas > max_particles) and (max_particles is not None) if subview: max_particles = int(max_particles) mask = np.zeros(n_gas + 1, dtype=bool) mask[-1] = True # Use the star particle always # randomly select particles to use m = np.random.rand(n_gas) ind = m.argsort()[0:max_particles] mask[ind] = True # Make a subview and create a reference to the complete snapshot complete_snapshot = f f = complete_snapshot[mask] # Scale gas mass m_scale = float(n_gas)/float(max_particles) f.g['mass'] *= m_scale if not est_eps: f.g['eps'] *= m_scale**(1.0/3) # Load stuff from the snapshot r = f.g['rxy'].astype(np.float32) cosine = (f.g['x']/r).in_units('1').astype(np.float32) sine = (f.g['y']/r).in_units('1').astype(np.float32) z = f.g['z'] vel = f.g['vel'] a = None # arbitrary initialization # Temporary filenames for running ChaNGa f_prefix = str(np.random.randint(0, 2**32)) f_name = f_prefix + '.std' p_name = f_prefix + '.param' # Update parameters p_temp = param.copy() p_temp['achInFile'] = f_name p_temp['achOutName'] = f_prefix p_temp['dDelta'] = 1e-10 if 'dDumpFrameTime' in p_temp: p_temp.pop('dDumpFrameTime') if 'dDumpFrameStep' in p_temp: p_temp.pop('dDumpFrameStep') # -------------------------------------------- # Estimate velocity from gravity only # -------------------------------------------- for iGrav in range(2): # Save files f.write(filename=f_name, fmt = pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') if iGrav == 0: # Run ChaNGa calculating all forces (for initial run) command = ICgen_utils.changa_command(p_name, changa_preset, changbin, '+gas +n 0') else: # Run ChaNGa, only calculating gravity (on second run) command = ICgen_utils.changa_command(p_name, changa_preset, changbin, '-gas +n 0') print command p = ICgen_utils.changa_run(command) p.wait() if (iGrav == 0) and est_eps: # Estimate the gravitational softening length on the first iteration smoothlength_file = f_prefix + '.000000.smoothlength' eps = ICgen_utils.est_eps(smoothlength_file) f.g['eps'] = eps # Load accelerations acc_name = f_prefix + '.000000.acc2' del a gc.collect() a = isaac.load_acc(acc_name, low_mem=True) gc.collect() # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Calculate cos(theta) where theta is angle above x-y plane cos = (r/np.sqrt(r**2 + z**2)).in_units('1').astype(np.float32) # Calculate radial acceleration times r^2 ar2 = (a[:,0]*cosine + a[:,1]*sine)*r**2 # Bin the data r_edges = np.linspace(r.min(), (1+np.spacing(2))*r.max(), nr + 1) ind, r_edges = isaac.digitize_threshold(r, min_per_bin, r_edges) ind -= 1 nr = len(r_edges) - 1 r_bins, ar2_mean, err = isaac.binned_mean(r, ar2, binedges=r_edges, \ weighted_bins=True) gc.collect() # Fit lines to ar2 vs cos for each radial bin m = np.zeros(nr) b = np.zeros(nr) for i in range(nr): mask = (ind == i) p = np.polyfit(cos[mask], ar2[mask], 1) m[i] = p[0] b[i] = p[1] # Interpolate the line fits m_spline = isaac.extrap1d(r_bins, m) b_spline = isaac.extrap1d(r_bins, b) # Calculate circular velocity ar2 = SimArray(m_spline(r)*cos + b_spline(r), ar2.units) gc.collect() v_calc = (np.sqrt(abs(ar2)/r)).in_units(vel.units) gc.collect() vel[:,0] = -v_calc*sine vel[:,1] = v_calc*cosine del v_calc gc.collect() # -------------------------------------------- # Estimate pressure/gas dynamics accelerations # -------------------------------------------- # Save files f.write(filename=f_name, fmt = pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, including SPH command = ICgen_utils.changa_command(p_name, changa_preset, changbin, '+gas -n 0') p = ICgen_utils.changa_run(command) p.wait() # Load accelerations acc_name = f_prefix + '.000000.acc2' a_total = isaac.load_acc(acc_name, low_mem=True) gc.collect() # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Estimate the accelerations due to pressure gradients/gas dynamics a_gas = a_total - a del a_total, a gc.collect() ar2_gas = (a_gas[:,0]*cosine + a_gas[:,1]*sine)*r**2 del a_gas gc.collect() logr_bins, ratio, err = isaac.binned_mean(np.log(r), ar2_gas/ar2, nbins=nr,\ weighted_bins=True) r_bins = np.exp(logr_bins) del ar2_gas gc.collect() ratio_spline = isaac.extrap1d(r_bins, ratio) # If not all the particles were used for calculating velocity, # Make sure to use them now if subview: # Re-scale mass back to normal f.g['mass'] /= m_scale # Scale eps appropriately f.g['eps'] /= m_scale**(1.0/3) complete_snapshot.g['eps'] = f.g['eps'][[0]] # Rename complete snapshot f = complete_snapshot # Calculate stuff for all particles r = f.g['rxy'] z = f.g['z'] cos = (r/np.sqrt(r**2 + z**2)).in_units('1').astype(np.float32) ar2 = SimArray(m_spline(r)*cos + b_spline(r), ar2.units) cosine = (f.g['x']/r).in_units('1').astype(np.float32) sine = (f.g['y']/r).in_units('1').astype(np.float32) vel = f.g['vel'] ar2_calc = ar2*(1 + ratio_spline(r)) del ar2 gc.collect() # Calculate velocity v = (np.sqrt(abs(ar2_calc)/r)).in_units(f.g['vel'].units) del ar2_calc gc.collect() vel[:,0] = -v*sine vel[:,1] = v*cosine return
def v_xy(f, param, changbin=None, nr=50, min_per_bin=100): """ Attempts to calculate the circular velocities for particles in a thin (not flat) keplerian disk. Requires ChaNGa **ARGUMENTS** f : tipsy snapshot For a gaseous disk param : dict a dictionary containing params for changa. (see isaac.configparser) changbin : str (OPTIONAL) If set, should be the full path to the ChaNGa executable. If None, an attempt to find ChaNGa is made nr : int (optional) number of radial bins to use when averaging over accelerations min_per_bin : int (optional) The minimum number of particles to be in each bin. If there are too few particles in a bin, it is merged with an adjacent bin. Thus, actual number of radial bins may be less than nr. **RETURNS** vel : SimArray An N by 3 SimArray of gas particle velocities. """ if changbin is None: # Try to find the ChaNGa binary full path changbin = os.popen('which ChaNGa').read().strip() # Load stuff from the snapshot x = f.g['x'] y = f.g['y'] z = f.g['z'] r = f.g['rxy'] vel0 = f.g['vel'].copy() # Remove units from all quantities r = isaac.strip_units(r) x = isaac.strip_units(x) y = isaac.strip_units(y) z = isaac.strip_units(z) # Temporary filenames for running ChaNGa f_prefix = str(np.random.randint(0, 2**32)) f_name = f_prefix + '.std' p_name = f_prefix + '.param' # Update parameters p_temp = param.copy() p_temp['achInFile'] = f_name p_temp['achOutName'] = f_prefix if 'dDumpFrameTime' in p_temp: p_temp.pop('dDumpFrameTime') if 'dDumpFrameStep' in p_temp: p_temp.pop('dDumpFrameStep') # -------------------------------------------- # Estimate velocity from gravity only # -------------------------------------------- # Note, accelerations due to gravity are calculated twice to be extra careful # This is so that any velocity dependent effects are properly accounted for # (although, ideally, there should be none) # The second calculation uses the updated velocities from the first for iGrav in range(2): # Save files f.write(filename=f_name, fmt=pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, only calculating gravity command = 'charmrun ++local ' + changbin + ' -gas -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a = isaac.load_acc(acc_name) # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # If a is not a vector, calculate radial acceleration. Otherwise, assume # a is the radial acceleration a_r = a[:, 0] * x / r + a[:, 1] * y / r # Make sure the units are correct then remove them a_r = isaac.match_units(a_r, a)[0] a_r = isaac.strip_units(a_r) # Calculate cos(theta) where theta is angle above x-y plane cos = r / np.sqrt(r**2 + z**2) ar2 = a_r * r**2 # Bin the data r_edges = np.linspace(r.min(), (1 + np.spacing(2)) * r.max(), nr + 1) ind, r_edges = isaac.digitize_threshold(r, min_per_bin, r_edges) ind -= 1 nr = len(r_edges) - 1 r_bins, ar2_mean, err = isaac.binned_mean(r, ar2, binedges=r_edges, \ weighted_bins=True) # Fit lines to ar2 vs cos for each radial bin m = np.zeros(nr) b = np.zeros(nr) for i in range(nr): mask = (ind == i) p = np.polyfit(cos[mask], ar2[mask], 1) m[i] = p[0] b[i] = p[1] # Interpolate the line fits m_spline = isaac.extrap1d(r_bins, m) b_spline = isaac.extrap1d(r_bins, b) # Calculate circular velocity ar2_calc = m_spline(r) * cos + b_spline(r) v_calc = np.sqrt(abs(ar2_calc) / r) vel = f.g['vel'].copy() v_calc = isaac.match_units(v_calc, vel)[0] vel[:, 0] = -v_calc * y / r vel[:, 1] = v_calc * x / r # Assign to f f.g['vel'] = vel # -------------------------------------------- # Estimate pressure/gas dynamics accelerations # -------------------------------------------- a_grav = a ar2_calc_grav = ar2_calc # Save files f.write(filename=f_name, fmt=pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, including SPH command = 'charmrun ++local ' + changbin + ' +gas -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a_total = isaac.load_acc(acc_name) # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Estimate the accelerations due to pressure gradients/gas dynamics a_gas = a_total - a_grav ar_gas = a_gas[:, 0] * x / r + a_gas[:, 1] * y / r ar_gas = isaac.strip_units(ar_gas) ar2_gas = ar_gas * r**2 logr_bins, ratio, err = isaac.binned_mean(np.log(r), ar2_gas/ar2_calc_grav, nbins=nr,\ weighted_bins=True) r_bins = np.exp(logr_bins) ratio_spline = isaac.extrap1d(r_bins, ratio) ar2_calc = ar2_calc_grav * (1 + ratio_spline(r)) a_calc = ar2_calc / r**2 v = np.sqrt(r * abs(a_calc)) v = isaac.match_units(v, vel0.units)[0] vel = vel0.copy() vel[:, 0] = -v * y / r vel[:, 1] = v * x / r # more cleanup f.g['vel'] = vel0 return vel
def v_xy(snapshot, param, changbin=None): """ Attempts to calculate the circular velocities for particles in a thin (not flat) keplerian disk. Requires ChaNGa ARGUMENTS: snapshot: a tipsy snapshot for a gaseous disk param: a dictionary containing params for changa. (see isaac.configparser) changbin: (OPTIONAL) If set, should be the full path to the ChaNGa executable. If None, an attempt to find ChaNGa is made """ if changbin is None: # Try to find the ChaNGa binary full path changbin = os.popen('which ChaNGa').read().strip() # -------------------------------------------- # Initialize # -------------------------------------------- # Load things from snapshot x = snapshot.g['x'] y = snapshot.g['y'] z = snapshot.g['z'] r = snapshot.g['rxy'] v_initial = snapshot.g['vel'].copy() # Temporary filenames for running ChaNGa f_prefix = str(np.random.randint(0, 2**32)) f_name = f_prefix + '.std' p_name = f_prefix + '.param' # Update parameters p_temp = param.copy() p_temp['achInFile'] = f_name p_temp['achOutName'] = f_prefix if 'dDumpFrameTime' in p_temp: p_temp.pop('dDumpFrameTime') if 'dDumpFrameStep' in p_temp: p_temp.pop('dDumpFrameStep') # -------------------------------------------- # Estimate velocity from gravity only # -------------------------------------------- # Save files snapshot.write(filename=f_name, fmt = pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, only calculating gravity command = 'charmrun ++local ' + changbin + ' -gas -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a = isaac.load_acc(acc_name) # Calculate radial acceleration a_r = a[:,0]*x/r + a[:,1]*y/r # circular velocity v = np.sqrt(abs(r*a_r)) # Assign snapshot.g['vel'][:,0] = -v*y/r snapshot.g['vel'][:,1] = v*x/r # -------------------------------------------- # Estimate velocity from gravity & sph (assuming bDoGas=1 in param) # -------------------------------------------- # Write file snapshot.write(filename=f_name, fmt = pynbody.tipsy.TipsySnap) # Run ChaNGa, only calculating gravity changbin = os.popen('which ChaNGa').read().strip() #command = 'charmrun ++local ' + changbin + ' +gas -n 0 ' + p_name command = 'charmrun ++local ' + changbin + ' -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a = isaac.load_acc(acc_name) # Calculate radial acceleration a_r = a[:,0]*x/r + a[:,1]*y/r # circular velocity v = np.sqrt(abs(r*a_r)) logv = np.log(v) logr = np.log(r) logr_bins, logv_mean, err = isaac.binned_mean(logr, logv, 50, \ weighted_bins=True) logv_spline = isaac.extrap1d(logr_bins, logv_mean) v_calc = np.exp(logv_spline(logr)) v_calc = isaac.match_units(v_calc, v_initial.units)[0] v_out = v_initial * 0.0 v_out[:,0] = -v_calc * y/r v_out[:,1] = v_calc * x/r # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Re-assign velocity to snapshot snapshot.g['vel'] = v_initial return v_out
def v_xy(f, param, changbin=None, nr=50, min_per_bin=100, changa_preset=None, \ max_particles=None, est_eps=True): """ Attempts to calculate the circular velocities for particles in a thin (not flat) keplerian disk. Also estimates gravitational softening (eps) for the gas particles Requires ChaNGa Note that this will change the velocities IN f **ARGUMENTS** f : tipsy snapshot For a gaseous disk param : dict a dictionary containing params for changa. (see isaac.configparser) changbin : str (OPTIONAL) If set, should be the full path to the ChaNGa executable. If None, an attempt to find ChaNGa is made nr : int (optional) number of radial bins to use when averaging over accelerations min_per_bin : int (optional) The minimum number of particles to be in each bin. If there are too few particles in a bin, it is merged with an adjacent bin. Thus, actual number of radial bins may be less than nr. changa_preset : str Which ChaNGa execution preset to use (ie 'mpi', 'local', ...). See ICgen_utils.changa_command max_particles : int or None Specifies the maximum number of particles to use for calculating accelerations and velocities. Setting a smaller number can speed up computation and save on memory but can yield noisier results. If None, max is unlimited. est_eps : bool Estimate eps (gravitational softening length). Default is True. If False, it is assumed eps has already been estimated **RETURNS** Nothing. Velocities are updated within f as is eps """ # If the snapshot has too many particles, randomly select gas particles # To use for calculating velocity and make a view of the snapshot n_gas = len(f) - 1 subview = (n_gas > max_particles) and (max_particles is not None) if subview: max_particles = int(max_particles) mask = np.zeros(n_gas + 1, dtype=bool) mask[-1] = True # Use the star particle always # randomly select particles to use m = np.random.rand(n_gas) ind = m.argsort()[0:max_particles] mask[ind] = True # Make a subview and create a reference to the complete snapshot complete_snapshot = f f = complete_snapshot[mask] # Scale gas mass m_scale = float(n_gas) / float(max_particles) f.g['mass'] *= m_scale if not est_eps: f.g['eps'] *= m_scale**(1.0 / 3) # Load stuff from the snapshot r = f.g['rxy'].astype(np.float32) cosine = (f.g['x'] / r).in_units('1').astype(np.float32) sine = (f.g['y'] / r).in_units('1').astype(np.float32) z = f.g['z'] vel = f.g['vel'] a = None # arbitrary initialization # Temporary filenames for running ChaNGa f_prefix = str(np.random.randint(0, 2**32)) f_name = f_prefix + '.std' p_name = f_prefix + '.param' # Update parameters p_temp = param.copy() p_temp['achInFile'] = f_name p_temp['achOutName'] = f_prefix p_temp['dDelta'] = 1e-10 if 'dDumpFrameTime' in p_temp: p_temp.pop('dDumpFrameTime') if 'dDumpFrameStep' in p_temp: p_temp.pop('dDumpFrameStep') # -------------------------------------------- # Estimate velocity from gravity only # -------------------------------------------- for iGrav in range(2): # Save files f.write(filename=f_name, fmt=pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') if iGrav == 0: # Run ChaNGa calculating all forces (for initial run) command = ICgen_utils.changa_command(p_name, changa_preset, changbin, '+gas +n 0') else: # Run ChaNGa, only calculating gravity (on second run) command = ICgen_utils.changa_command(p_name, changa_preset, changbin, '-gas +n 0') print command p = ICgen_utils.changa_run(command) p.wait() if (iGrav == 0) and est_eps: # Estimate the gravitational softening length on the first iteration smoothlength_file = f_prefix + '.000000.smoothlength' eps = ICgen_utils.est_eps(smoothlength_file) f.g['eps'] = eps # Load accelerations acc_name = f_prefix + '.000000.acc2' del a gc.collect() a = isaac.load_acc(acc_name, low_mem=True) gc.collect() # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Calculate cos(theta) where theta is angle above x-y plane cos = (r / np.sqrt(r**2 + z**2)).in_units('1').astype(np.float32) # Calculate radial acceleration times r^2 ar2 = (a[:, 0] * cosine + a[:, 1] * sine) * r**2 # Bin the data r_edges = np.linspace(r.min(), (1 + np.spacing(2)) * r.max(), nr + 1) ind, r_edges = isaac.digitize_threshold(r, min_per_bin, r_edges) ind -= 1 nr = len(r_edges) - 1 r_bins, ar2_mean, err = isaac.binned_mean(r, ar2, binedges=r_edges, \ weighted_bins=True) gc.collect() # Fit lines to ar2 vs cos for each radial bin m = np.zeros(nr) b = np.zeros(nr) for i in range(nr): mask = (ind == i) p = np.polyfit(cos[mask], ar2[mask], 1) m[i] = p[0] b[i] = p[1] # Interpolate the line fits m_spline = isaac.extrap1d(r_bins, m) b_spline = isaac.extrap1d(r_bins, b) # Calculate circular velocity ar2 = SimArray(m_spline(r) * cos + b_spline(r), ar2.units) gc.collect() v_calc = (np.sqrt(abs(ar2) / r)).in_units(vel.units) gc.collect() vel[:, 0] = -v_calc * sine vel[:, 1] = v_calc * cosine del v_calc gc.collect() # -------------------------------------------- # Estimate pressure/gas dynamics accelerations # -------------------------------------------- # Save files f.write(filename=f_name, fmt=pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, including SPH command = ICgen_utils.changa_command(p_name, changa_preset, changbin, '+gas -n 0') p = ICgen_utils.changa_run(command) p.wait() # Load accelerations acc_name = f_prefix + '.000000.acc2' a_total = isaac.load_acc(acc_name, low_mem=True) gc.collect() # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Estimate the accelerations due to pressure gradients/gas dynamics a_gas = a_total - a del a_total, a gc.collect() ar2_gas = (a_gas[:, 0] * cosine + a_gas[:, 1] * sine) * r**2 del a_gas gc.collect() logr_bins, ratio, err = isaac.binned_mean(np.log(r), ar2_gas/ar2, nbins=nr,\ weighted_bins=True) r_bins = np.exp(logr_bins) del ar2_gas gc.collect() ratio_spline = isaac.extrap1d(r_bins, ratio) # If not all the particles were used for calculating velocity, # Make sure to use them now if subview: # Re-scale mass back to normal f.g['mass'] /= m_scale # Scale eps appropriately f.g['eps'] /= m_scale**(1.0 / 3) complete_snapshot.g['eps'] = f.g['eps'][[0]] # Rename complete snapshot f = complete_snapshot # Calculate stuff for all particles r = f.g['rxy'] z = f.g['z'] cos = (r / np.sqrt(r**2 + z**2)).in_units('1').astype(np.float32) ar2 = SimArray(m_spline(r) * cos + b_spline(r), ar2.units) cosine = (f.g['x'] / r).in_units('1').astype(np.float32) sine = (f.g['y'] / r).in_units('1').astype(np.float32) vel = f.g['vel'] ar2_calc = ar2 * (1 + ratio_spline(r)) del ar2 gc.collect() # Calculate velocity v = (np.sqrt(abs(ar2_calc) / r)).in_units(f.g['vel'].units) del ar2_calc gc.collect() vel[:, 0] = -v * sine vel[:, 1] = v * cosine return
def v_xy(snapshot, param, changbin=None): """ Attempts to calculate the circular velocities for particles in a thin (not flat) keplerian disk. Requires ChaNGa ARGUMENTS: snapshot: a tipsy snapshot for a gaseous disk param: a dictionary containing params for changa. (see isaac.configparser) changbin: (OPTIONAL) If set, should be the full path to the ChaNGa executable. If None, an attempt to find ChaNGa is made """ if changbin is None: # Try to find the ChaNGa binary full path changbin = os.popen('which ChaNGa').read().strip() # -------------------------------------------- # Initialize # -------------------------------------------- # Load things from snapshot x = snapshot.g['x'] y = snapshot.g['y'] z = snapshot.g['z'] r = snapshot.g['rxy'] v_initial = snapshot.g['vel'].copy() # Temporary filenames for running ChaNGa f_prefix = str(np.random.randint(0, 2**32)) f_name = f_prefix + '.std' p_name = f_prefix + '.param' # Update parameters p_temp = param.copy() p_temp['achInFile'] = f_name p_temp['achOutName'] = f_prefix if 'dDumpFrameTime' in p_temp: p_temp.pop('dDumpFrameTime') if 'dDumpFrameStep' in p_temp: p_temp.pop('dDumpFrameStep') # -------------------------------------------- # Estimate velocity from gravity only # -------------------------------------------- # Save files snapshot.write(filename=f_name, fmt=pynbody.tipsy.TipsySnap) isaac.configsave(p_temp, p_name, ftype='param') # Run ChaNGa, only calculating gravity command = 'charmrun ++local ' + changbin + ' -gas -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a = isaac.load_acc(acc_name) # Calculate radial acceleration a_r = a[:, 0] * x / r + a[:, 1] * y / r # circular velocity v = np.sqrt(abs(r * a_r)) # Assign snapshot.g['vel'][:, 0] = -v * y / r snapshot.g['vel'][:, 1] = v * x / r # -------------------------------------------- # Estimate velocity from gravity & sph (assuming bDoGas=1 in param) # -------------------------------------------- # Write file snapshot.write(filename=f_name, fmt=pynbody.tipsy.TipsySnap) # Run ChaNGa, only calculating gravity changbin = os.popen('which ChaNGa').read().strip() #command = 'charmrun ++local ' + changbin + ' +gas -n 0 ' + p_name command = 'charmrun ++local ' + changbin + ' -n 0 ' + p_name p = subprocess.Popen(command.split(), stdout=subprocess.PIPE) while p.poll() is None: time.sleep(0.1) # Load accelerations acc_name = f_prefix + '.000000.acc2' a = isaac.load_acc(acc_name) # Calculate radial acceleration a_r = a[:, 0] * x / r + a[:, 1] * y / r # circular velocity v = np.sqrt(abs(r * a_r)) logv = np.log(v) logr = np.log(r) logr_bins, logv_mean, err = isaac.binned_mean(logr, logv, 50, \ weighted_bins=True) logv_spline = isaac.extrap1d(logr_bins, logv_mean) v_calc = np.exp(logv_spline(logr)) v_calc = isaac.match_units(v_calc, v_initial.units)[0] v_out = v_initial * 0.0 v_out[:, 0] = -v_calc * y / r v_out[:, 1] = v_calc * x / r # Clean-up for fname in glob.glob(f_prefix + '*'): os.remove(fname) # Re-assign velocity to snapshot snapshot.g['vel'] = v_initial return v_out