def scale_to_standard(particles, convert_nbody=None, smoothing_length_squared=zero, virial_ratio=0.5): """ Scale the particles to a standard NBODY model with G=1, total_mass=1, and virial_radius=1 (or potential_energy=-0.5). In virial equilibrium (virial_ratio=0.5, default) the kinetic_energy=0.25 and the velocity_dispersion=1/sqrt(2). :argument convert_nbody: the scaling is in nbody units, when the particles are in si units a convert_nbody is needed :argument smoothing_length_squared: needed for calculating the potential energy correctly. :argument virial_ratio: scale velocities to Q=K/|U|, (kinetic/potential energy); Q = virial_ratio > 0.5: supervirial, will expand Q = virial_ratio < 0.5: subvirial, will collapse """ if not convert_nbody is None: particles = ParticlesWithUnitsConverted( particles, convert_nbody.as_converter_from_generic_to_si()) if not smoothing_length_squared is zero: smoothing_length_squared = convert_nbody.to_nbody( smoothing_length_squared) # Proper order is to scale mass, then length, then velocities. # Simple length scaling for the potential works only in the # unsoftened case. In general, it may not be possible to force # the potential to -0.5, so perhaps best to stop after the simple # scaling. We can always scale the velocities to get the correct # virial ratio (and hence virial equilibrium). total_mass = particles.mass.sum() scale_factor = ((1 | total_mass.unit) / total_mass) particles.mass *= scale_factor potential_energy \ = particles.potential_energy(G=nbody_system.G, smoothing_length_squared = smoothing_length_squared) target_energy = -0.5 | nbody_system.energy scale_factor = (potential_energy / target_energy) # unsoftened only... particles.position *= scale_factor if smoothing_length_squared == zero: potential_energy = target_energy else: potential_energy = particles.potential_energy( G=nbody_system.G, smoothing_length_squared=smoothing_length_squared) if virial_ratio == 0: scale_factor = 0 else: scale_factor = numpy.sqrt( abs(virial_ratio * potential_energy) / particles.kinetic_energy()) particles.velocity *= scale_factor
def scale_to_standard(particles, convert_nbody = None, smoothing_length_squared = zero, virial_ratio = 0.5): """ Scale the particles to a standard NBODY model with G=1, total_mass=1, and virial_radius=1 (or potential_energy=-0.5). In virial equilibrium (virial_ratio=0.5, default) the kinetic_energy=0.25 and the velocity_dispersion=1/sqrt(2). :argument convert_nbody: the scaling is in nbody units, when the particles are in si units a convert_nbody is needed :argument smoothing_length_squared: needed for calculating the potential energy correctly. :argument virial_ratio: scale velocities to Q=K/|U|, (kinetic/potential energy); Q = virial_ratio > 0.5: supervirial, will expand Q = virial_ratio < 0.5: subvirial, will collapse """ if not convert_nbody is None: particles = ParticlesWithUnitsConverted(particles, convert_nbody.as_converter_from_generic_to_si()) if not smoothing_length_squared is zero: smoothing_length_squared = convert_nbody.to_nbody(smoothing_length_squared) # Proper order is to scale mass, then length, then velocities. # Simple length scaling for the potential works only in the # unsoftened case. In general, it may not be possible to force # the potential to -0.5, so perhaps best to stop after the simple # scaling. We can always scale the velocities to get the correct # virial ratio (and hence virial equilibrium). total_mass = particles.mass.sum() scale_factor = ((1 | total_mass.unit) / total_mass) particles.mass *= scale_factor potential_energy \ = particles.potential_energy(G=nbody_system.G, smoothing_length_squared = smoothing_length_squared) target_energy = -0.5 | nbody_system.energy scale_factor = (potential_energy / target_energy) # unsoftened only... particles.position *= scale_factor if smoothing_length_squared == zero: potential_energy = target_energy else: potential_energy = particles.potential_energy(G=nbody_system.G, smoothing_length_squared = smoothing_length_squared) if virial_ratio == 0: scale_factor = 0 else: scale_factor = numpy.sqrt(abs(virial_ratio*potential_energy) / particles.kinetic_energy()) particles.velocity *= scale_factor