def _new_galactics_model(halo_number_of_particles, unit_system_converter=None, do_scale=False, verbose=False, **keyword_arguments): code = keyword_arguments.pop("code") instance = code(unit_converter=unit_system_converter) instance.parameters.halo_number_of_particles = halo_number_of_particles for (key, value) in keyword_arguments.iteritems(): setattr(instance.parameters, key, value) if verbose: print "adopted galaxy model parameters:" print instance.parameters instance.generate_particles() result = instance.particles.copy() if hasattr(instance, "gas_particles") and len(instance.gas_particles) > 0: resultgas = instance.gas_particles.copy() else: resultgas = Particles() instance.stop() if len(resultgas) > 0: allpart = ParticlesSuperset([result, resultgas]) else: allpart = result allpart.move_to_center() # do_scale *is* possible for case with unit converter # note that in case of scaling the output galaxy parameters may be very different from the model # parameters input if do_scale: print "Warning: do_scale for a large galactics model may be very slow" if verbose: print "Warning: do_scale typically changes the galaxy scale parameters quite a lot from the input parameters" if len(resultgas) > 0: # this is fixable raise Exception( "scaling of galaxy models with gas currently not possible") allpart.scale_to_standard(convert_nbody=unit_system_converter) if not unit_system_converter is None: result = ParticlesWithUnitsConverted( result, unit_system_converter.as_converter_from_si_to_generic()) result = result.copy() if len(resultgas) > 0: resultgas = ParticlesWithUnitsConverted( resultgas, unit_system_converter.as_converter_from_si_to_generic()) resultgas = resultgas.copy() if len(resultgas) > 0: # resultincludes the gas particles (but not under the same keys) return resultgas, result else: return result
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 _new_galactics_model(halo_number_of_particles, unit_system_converter=None, do_scale=False, verbose=False, **keyword_arguments): code=keyword_arguments.pop("code") instance = code(unit_converter=unit_system_converter, redirection="none" if verbose else "null") instance.parameters.halo_number_of_particles = halo_number_of_particles for (key, value) in keyword_arguments.iteritems(): setattr(instance.parameters, key, value) if verbose: print "adopted galaxy model parameters:" print instance.parameters instance.generate_particles() result = instance.particles.copy() if hasattr(instance,"gas_particles") and len(instance.gas_particles)>0: resultgas=instance.gas_particles.copy() else: resultgas=Particles() instance.stop() if len(resultgas)>0: allpart=ParticlesSuperset([result, resultgas]) else: allpart=result allpart.move_to_center() # do_scale *is* possible for case with unit converter # note that in case of scaling the output galaxy parameters may be very different from the model # parameters input if do_scale: print "Warning: do_scale for a large galactics model may be very slow" if verbose: print "Warning: do_scale typically changes the galaxy scale parameters quite a lot from the input parameters" if len(resultgas)>0: # this is fixable raise Exception("scaling of galaxy models with gas currently not possible") allpart.scale_to_standard(convert_nbody=unit_system_converter) if not unit_system_converter is None: result = ParticlesWithUnitsConverted(result, unit_system_converter.as_converter_from_si_to_generic()) result = result.copy() if len(resultgas)>0: resultgas = ParticlesWithUnitsConverted(resultgas, unit_system_converter.as_converter_from_si_to_generic()) resultgas = resultgas.copy() if len(resultgas)>0: # resultincludes the gas particles (but not under the same keys) return resultgas, result else: return result
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 _new_galactics_model(halo_number_of_particles, unit_system_converter=None, do_scale=False, **keyword_arguments): instance = GalactICs(unit_converter=unit_system_converter) instance.parameters.halo_number_of_particles = halo_number_of_particles for (key, value) in keyword_arguments.iteritems(): setattr(instance.parameters, key, value) instance.generate_particles() result = instance.particles.copy() instance.stop() result.move_to_center() if do_scale: result.scale_to_standard(convert_nbody=unit_system_converter) if not unit_system_converter is None: result = ParticlesWithUnitsConverted(result, unit_system_converter.as_converter_from_si_to_generic()) result = result.copy() return result
def new_halogen_model(number_of_particles, convert_nbody=None, do_scale=False, redirection='null', **keyword_arguments): """ Create an alpha-beta-gamma-model using Halogen with the given number of particles. Returns a set of equal-mass particles self-consistently sampled from the spherically symmetric density distribution defined by the alpha, beta, and gamma parameters. The model is centered around the origin. Positions and velocities are optionally scaled such that the kinetic and potential energies are 0.25 and -0.5 in nbody-units, respectively. The alpha, beta, and gamma parameters are (of course) required, but all other Halogen parameters can be used too, e.g. new_halogen_model(..., black_hole_mass = 1.0e6 | units.MSun) will set halogen.parameters.black_hole_mass to this value. See help(Halogen().parameters) for an overview of the Halogen parameters. :argument number_of_particles: Number of particles to generate in the model :argument convert_nbody: When given will convert the resulting set to SI units :argument do_scale: scale the result to exact nbody units (M=1, K=0.25, U=-0.5) :argument alpha: alpha parameter in density profile (see amuse/community/halogen/src/doc for details) :argument beta: beta parameter in density profile (see amuse/community/halogen/src/doc for details) :argument gamma: gamma parameter in density profile (see amuse/community/halogen/src/doc for details) """ instance = Halogen(unit_converter=convert_nbody, redirection=redirection) instance.parameters.number_of_particles = number_of_particles for (key, value) in keyword_arguments.items(): setattr(instance.parameters, key, value) instance.generate_particles() result = instance.particles.copy() instance.stop() result.move_to_center() if do_scale: result.scale_to_standard() if not convert_nbody is None: result = ParticlesWithUnitsConverted( result, convert_nbody.as_converter_from_si_to_generic()) result = result.copy() return result
def new_limepy_model(*args, **kwargs): conv = kwargs.pop("converter", None) l = Limepy(*args, **kwargs) p = l.result if conv is not None: p = ParticlesWithUnitsConverted(p, conv.as_converter_from_si_to_generic()) return p
def new_halogen_model(number_of_particles, convert_nbody = None, do_scale = False, redirection = 'null', **keyword_arguments): """ Create an alpha-beta-gamma-model using Halogen with the given number of particles. Returns a set of equal-mass particles self-consistently sampled from the spherically symmetric density distribution defined by the alpha, beta, and gamma parameters. The model is centered around the origin. Positions and velocities are optionally scaled such that the kinetic and potential energies are 0.25 and -0.5 in nbody-units, respectively. The alpha, beta, and gamma parameters are (of course) required, but all other Halogen parameters can be used too, e.g. new_halogen_model(..., black_hole_mass = 1.0e6 | units.MSun) will set halogen.parameters.black_hole_mass to this value. See help(Halogen().parameters) for an overview of the Halogen parameters. :argument number_of_particles: Number of particles to generate in the model :argument convert_nbody: When given will convert the resulting set to SI units :argument do_scale: scale the result to exact nbody units (M=1, K=0.25, U=-0.5) :argument alpha: alpha parameter in density profile (see amuse/community/halogen/src/doc for details) :argument beta: beta parameter in density profile (see amuse/community/halogen/src/doc for details) :argument gamma: gamma parameter in density profile (see amuse/community/halogen/src/doc for details) """ instance = Halogen(unit_converter=convert_nbody, redirection=redirection) instance.parameters.number_of_particles = number_of_particles for (key, value) in keyword_arguments.iteritems(): setattr(instance.parameters, key, value) instance.generate_particles() result = instance.particles.copy() instance.stop() result.move_to_center() if do_scale: result.scale_to_standard() if not convert_nbody is None: result = ParticlesWithUnitsConverted(result, convert_nbody.as_converter_from_si_to_generic()) result = result.copy() return result
def result(self): masses, x,y,z, vx,vy,vz, internal_energies = self.new_model() result = Particles(self.actualN) result.mass = nbody_system.mass.new_quantity(masses) result.x = nbody_system.length.new_quantity(x) result.y = nbody_system.length.new_quantity(y) result.z = nbody_system.length.new_quantity(z) result.vx = nbody_system.speed.new_quantity(vx) result.vy = nbody_system.speed.new_quantity(vy) result.vz = nbody_system.speed.new_quantity(vz) result.u = nbody_system.specific_energy.new_quantity(internal_energies) if not self.convert_nbody is None: result = ParticlesWithUnitsConverted(result, self.convert_nbody.as_converter_from_si_to_generic()) result = result.copy() return result
def result(self): masses, positions, velocities, internal_energies = self.new_model() result = Particles(self.actual_number_of_particles) result.mass = nbody_system.mass.new_quantity(masses) result.position = nbody_system.length.new_quantity(positions) result.velocity = nbody_system.speed.new_quantity(velocities) result.u = nbody_system.specific_energy.new_quantity(internal_energies) result.position -= result.center_of_mass() if self.do_scale: scale_factor = (result.potential_energy(G=nbody_system.G)) / (-0.5 | nbody_system.energy) result.position *= scale_factor if not self.convert_nbody is None: result = ParticlesWithUnitsConverted(result, self.convert_nbody.as_converter_from_si_to_generic()) result = result.copy() return result
def make_model(self): call=[self._exec]+self.arguments() print(call) mameclot=Popen(call, stdout=PIPE,stderr=PIPE,executable=os.path.join(self._bin_path,self._exec)) (out,err)=mameclot.communicate() print(err) outsplit=out.decode().strip().split("\n") errsplit=err.decode().strip().split("\n") if self.mass_ratio==0: nline=errsplit[6].split() mline=errsplit[7].split() rline=errsplit[8].split() N1=int(nline[2]) N2=0 mscale=(float(mline[4])/float(mline[2])) | units.MSun rscale=(float(rline[4])/float(mline[2])) | units.parsec else: nline=errsplit[8].split() n2line=errsplit[22].split() mline=errsplit[9].split() rline=errsplit[10].split() N1=int(nline[2]) N2=int(n2line[2]) mscale=(float(mline[4])/float(mline[2])) | units.MSun rscale=(float(rline[4])/float(mline[2])) | units.parsec print(N1,N2) N=len( outsplit) parts=Particles(N) masses=numpy.zeros((N,)) energy=numpy.zeros((N,)) position=numpy.zeros((N,3)) velocity=numpy.zeros((N,3)) for i,line in enumerate(outsplit): l=line.split() masses[i]=float(l[0]) position[i,0:3]=[float(l[1]),float(l[2]),float(l[3])] velocity[i,0:3]=[float(l[4]),float(l[5]),float(l[6])] energy[i]=float(l[7]) parts.mass=masses | nbody_system.mass parts.position=position | nbody_system.length parts.velocity=velocity | nbody_system.speed parts.specific_energy=energy| nbody_system.specific_energy parts.move_to_center() if self.convert_to_physical: print("mass scale:", mscale) print("length scale:", rscale) convert_nbody=nbody_system.nbody_to_si(mscale,rscale) parts = ParticlesWithUnitsConverted(parts, convert_nbody.as_converter_from_si_to_generic()) parts = parts.copy() self._all=parts self._cluster1=parts[:N1] self._cluster2=parts[N1:]
def test6(self): print "Test all particle attributes using Hop - each different function creates its own instance of Hop" numpy.random.seed(123) nbody_plummer = new_plummer_sphere(100) nbody_plummer.mass = new_salpeter_mass_distribution_nbody(100) # Each different function creates its own instance of Hop result = nbody_plummer.new_particle_from_cluster_core(reuse_hop=True) result = nbody_plummer.bound_subset(G=nbody_system.G, reuse_hop=True) result = nbody_plummer.mass_segregation_Gini_coefficient( reuse_hop=True) result = nbody_plummer.LagrangianRadii(reuse_hop=True) result = nbody_plummer.densitycentre_coreradius_coredens( reuse_hop=True) converter = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.parsec) si_plummer = ParticlesWithUnitsConverted( nbody_plummer, converter.as_converter_from_si_to_nbody()) functions_using_hop = [ si_plummer.new_particle_from_cluster_core, si_plummer.bound_subset, si_plummer.mass_segregation_Gini_coefficient, si_plummer.LagrangianRadii, si_plummer.densitycentre_coreradius_coredens ] # Each fails since the Hop instance it tries to reuse has a different unit_converter for function_using_hop in functions_using_hop: self.assertRaises( ConvertArgumentsException, function_using_hop, unit_converter=converter, expected_message= "error while converting parameter 'mass', error: Cannot express kg in mass, the units do not have the same bases" ) # Close all Hop instances: nbody_results = [] nbody_results.append( nbody_plummer.new_particle_from_cluster_core(reuse_hop=False)) nbody_results.append( nbody_plummer.bound_subset(G=nbody_system.G, reuse_hop=False)) nbody_results.append( nbody_plummer.mass_segregation_Gini_coefficient(reuse_hop=False)) nbody_results.append(nbody_plummer.LagrangianRadii(reuse_hop=False)) nbody_results.append( nbody_plummer.densitycentre_coreradius_coredens(reuse_hop=False)) # Now it works, because the Hop instances were closed, and new ones will be instantiated si_results = [] for function_using_hop in functions_using_hop: si_results.append(function_using_hop(unit_converter=converter)) convert = converter.as_converter_from_si_to_nbody() self.assertAlmostRelativeEqual( si_results[0].position, ParticlesWithUnitsConverted(nbody_results[0].as_set(), convert)[0].position) self.assertAlmostRelativeEqual( si_results[1].position, ParticlesWithUnitsConverted(nbody_results[1], convert).position) self.assertAlmostRelativeEqual(si_results[2], nbody_results[2], places=10) self.assertAlmostRelativeEqual(si_results[3][0], convert.from_target_to_source( nbody_results[3][0]), places=10) for in_si, in_nbody in zip(si_results[4], nbody_results[4]): self.assertAlmostRelativeEqual( in_si, convert.from_target_to_source(in_nbody), places=10)