diff --git a/src/amuse/community/interface/gd/__init__.py b/src/amuse/community/interface/gd/__init__.py new file mode 100644 index 0000000000..98cdbabcec --- /dev/null +++ b/src/amuse/community/interface/gd/__init__.py @@ -0,0 +1,23 @@ +from amuse.support.interface import InCodeComponentImplementation +from amuse.units import nbody_system +from amuse.units import generic_unit_converter +from amuse.community.interface import common + +from amuse.rfi.core import legacy_function +from amuse.rfi.core import LegacyFunctionSpecification + +from .gravitational_dynamics import ( + GravitationalDynamicsInterface, + GravitationalDynamicsDocumentation, + GravitationalDynamics, +) +from .gravity_field import ( + SinglePointGravityFieldInterface, + GravityFieldInterface, + GravityFieldCode, +) +from .gravitational_dynamics_64 import ( + GravitationalDynamics64Interface, + GravitationalDynamics64Documentation, + GravitationalDynamics64, +) diff --git a/src/amuse/community/interface/gd.py b/src/amuse/community/interface/gd/gravitational_dynamics.py similarity index 92% rename from src/amuse/community/interface/gd.py rename to src/amuse/community/interface/gd/gravitational_dynamics.py index 2a0d9059ac..c3bc929379 100644 --- a/src/amuse/community/interface/gd.py +++ b/src/amuse/community/interface/gd/gravitational_dynamics.py @@ -2,9 +2,7 @@ Stellar Dynamics Interface Definition """ -from amuse.support.interface import InCodeComponentImplementation from amuse.units import nbody_system -from amuse.units import generic_unit_converter from amuse.community.interface import common from amuse.rfi.core import legacy_function @@ -1132,104 +1130,6 @@ def get_index_of_next_particle(): return function -class GravityFieldInterface: - """ - Codes implementing the gravity field interface provide functions to - calculate the force and potential energy fields at any point. - """ - - @legacy_function - def get_gravity_at_point(): - """ - Get the gravitational acceleration at the given points. To calculate - the force on bodies at those points, multiply with the mass of the - bodies - """ - function = LegacyFunctionSpecification() - for x in ["eps", "x", "y", "z"]: - function.addParameter( - x, dtype="float64", direction=function.IN, unit=nbody_system.length - ) - for x in ["ax", "ay", "az"]: - function.addParameter( - x, - dtype="float64", - direction=function.OUT, - unit=nbody_system.acceleration, - ) - function.addParameter("npoints", dtype="i", direction=function.LENGTH) - function.result_type = "int32" - function.must_handle_array = True - return function - - @legacy_function - def get_potential_at_point(): - """ - Determine the gravitational potential on any given point - """ - function = LegacyFunctionSpecification() - for x in ["eps", "x", "y", "z"]: - function.addParameter( - x, dtype="float64", direction=function.IN, unit=nbody_system.length - ) - for x in ["phi"]: - function.addParameter( - x, dtype="float64", direction=function.OUT, unit=nbody_system.potential - ) - function.addParameter("npoints", dtype="i", direction=function.LENGTH) - function.result_type = "int32" - function.must_handle_array = True - return function - - -class SinglePointGravityFieldInterface: - """ - Codes implementing the gravity field interface provide functions to - calculate the force and potential energy fields at any point. - """ - - @legacy_function - def get_gravity_at_point(): - """ - Get the gravitational acceleration at the given points. To calculate - the force on bodies at those points, multiply with the mass of the - bodies - """ - function = LegacyFunctionSpecification() - for x in ["eps", "x", "y", "z"]: - function.addParameter( - x, dtype="float64", direction=function.IN, unit=nbody_system.length - ) - for x in ["ax", "ay", "az"]: - function.addParameter( - x, - dtype="float64", - direction=function.OUT, - unit=nbody_system.acceleration, - ) - function.result_type = "int32" - function.can_handle_array = True - return function - - @legacy_function - def get_potential_at_point(): - """ - Determine the gravitational potential on any given point - """ - function = LegacyFunctionSpecification() - for x in ["eps", "x", "y", "z"]: - function.addParameter( - x, dtype="float64", direction=function.IN, unit=nbody_system.length - ) - for x in ["phi"]: - function.addParameter( - x, dtype="float64", direction=function.OUT, unit=nbody_system.potential - ) - function.result_type = "int32" - function.can_handle_array = True - return function - - class GravitationalDynamicsDocumentation: def __get__(self, instance, owner): @@ -1610,10 +1510,3 @@ def reset(self): def get_total_energy(self): return self.get_potential_energy() + self.get_kinetic_energy() - - -class GravityFieldCode: - - def define_state(self, handler): - handler.add_method("RUN", "get_gravity_at_point") - handler.add_method("RUN", "get_potential_at_point") diff --git a/src/amuse/community/interface/gd/gravitational_dynamics_64.py b/src/amuse/community/interface/gd/gravitational_dynamics_64.py new file mode 100644 index 0000000000..5138d4569e --- /dev/null +++ b/src/amuse/community/interface/gd/gravitational_dynamics_64.py @@ -0,0 +1,1512 @@ +""" +Stellar Dynamics Interface Definition +""" + +from amuse.units import nbody_system +from amuse.community.interface import common + +from amuse.rfi.core import legacy_function +from amuse.rfi.core import LegacyFunctionSpecification + + +class GravitationalDynamics64Interface(common.CommonCodeInterface): + + @legacy_function + def new_particle(): + """ + Define a new particle in the stellar dynamics code. The particle is + initialized with the provided mass, radius, position and velocity. This + function returns an index that can be used to refer to this particle. + """ + function = LegacyFunctionSpecification() + function.can_handle_array = True + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.OUT, + description=( + "An index assigned to the newly created particle. " + "This index is supposed to be a local index for the code " + "(and not valid in other instances of the code or in other " + "codes)" + ), + ) + + function.addParameter( + "mass", + dtype="float64", + direction=function.IN, + description="The mass of the particle", + ) + function.addParameter( + "x", + dtype="float64", + direction=function.IN, + description="The initial position vector of the particle", + ) + function.addParameter( + "y", + dtype="float64", + direction=function.IN, + description="The initial position vector of the particle", + ) + function.addParameter( + "z", + dtype="float64", + direction=function.IN, + description="The initial position vector of the particle", + ) + function.addParameter( + "vx", + dtype="float64", + direction=function.IN, + description="The initial velocity vector of the particle", + ) + function.addParameter( + "vy", + dtype="float64", + direction=function.IN, + description="The initial velocity vector of the particle", + ) + function.addParameter( + "vz", + dtype="float64", + direction=function.IN, + description="The initial velocity vector of the particle", + ) + function.addParameter( + "radius", + dtype="float64", + direction=function.IN, + description="The radius of the particle", + default=0, + ) + function.result_type = "int32" + function.result_doc = """ 0 - OK + particle was created and added to the model + -1 - ERROR + particle could not be created""" + return function + + @legacy_function + def delete_particle(): + """ + Remove the definition of particle from the code. After calling this + function the particle is no longer part of the model evolution. It is + up to the code if the index will be reused. + This function is optional. + """ + function = LegacyFunctionSpecification() + function.can_handle_array = True + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to be removed. This index must have " + "been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + particle was removed from the model + -1 - ERROR + particle could not be removed + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def get_state(): + """ + Retrieve the current state of a particle. The *minimal* information of + a stellar dynamics particle (mass, radius, position and velocity) is + returned. + """ + function = LegacyFunctionSpecification() + function.can_handle_array = True + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the state from. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "mass", + dtype="float64", + direction=function.OUT, + description="The current mass of the particle", + ) + function.addParameter( + "x", + dtype="float64", + direction=function.OUT, + description="The current position vector of the particle", + ) + function.addParameter( + "y", + dtype="float64", + direction=function.OUT, + description="The current position vector of the particle", + ) + function.addParameter( + "z", + dtype="float64", + direction=function.OUT, + description="The current position vector of the particle", + ) + function.addParameter( + "vx", + dtype="float64", + direction=function.OUT, + description="The current velocity vector of the particle", + ) + function.addParameter( + "vy", + dtype="float64", + direction=function.OUT, + description="The current velocity vector of the particle", + ) + function.addParameter( + "vz", + dtype="float64", + direction=function.OUT, + description="The current velocity vector of the particle", + ) + function.addParameter( + "radius", + dtype="float64", + direction=function.OUT, + description="The current radius of the particle", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + particle was removed from the model + -1 - ERROR + particle could not be found + """ + return function + + @legacy_function + def set_state(): + """ + Update the current state of a particle. The *minimal* information of a + stellar dynamics particle (mass, radius, position and velocity) is + updated. + """ + function = LegacyFunctionSpecification() + function.can_handle_array = True + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle for which the state is to be updated. " + "This index must have been returned by an earlier call to " + ":meth:`new_particle`" + ), + ) + function.addParameter( + "mass", + dtype="float64", + direction=function.IN, + description="The new mass of the particle", + ) + function.addParameter( + "x", + dtype="float64", + direction=function.IN, + description="The new position vector of the particle", + ) + function.addParameter( + "y", + dtype="float64", + direction=function.IN, + description="The new position vector of the particle", + ) + function.addParameter( + "z", + dtype="float64", + direction=function.IN, + description="The new position vector of the particle", + ) + function.addParameter( + "vx", + dtype="float64", + direction=function.IN, + description="The new velocity vector of the particle", + ) + function.addParameter( + "vy", + dtype="float64", + direction=function.IN, + description="The new velocity vector of the particle", + ) + function.addParameter( + "vz", + dtype="float64", + direction=function.IN, + description="The new velocity vector of the particle", + ) + function.addParameter( + "radius", + dtype="float64", + direction=function.IN, + description="The new radius of the particle", + default=0, + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + particle was found in the model and the information was set + -1 - ERROR + particle could not be found + -2 - ERROR + code does not support updating of a particle + -3 - ERROR + not yet implemented + """ + return function + + @legacy_function + def get_mass(): + """ + Retrieve the mass of a particle. Mass is a scalar property of a + particle, this function has one OUT argument. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the state from. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "mass", + dtype="float64", + direction=function.OUT, + description="The current mass of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + particle was removed from the model + -1 - ERROR + particle could not be found + """ + return function + + @legacy_function + def set_mass(): + """ + Update the mass of a particle. Mass is a scalar property of a particle. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle for which the state is to be updated. " + "This index must have been returned by an earlier call to " + ":meth:`new_particle`" + ), + ) + function.addParameter( + "mass", + dtype="float64", + direction=function.IN, + description="The new mass of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + particle was found in the model and the information was set + -1 - ERROR + particle could not be found + -2 - ERROR + code does not support updating of a particle + """ + return function + + @legacy_function + def get_radius(): + """ + Retrieve the radius of a particle. Radius is a scalar property of a + particle, this function has one OUT argument. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the radius of. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "radius", + dtype="float64", + direction=function.OUT, + description="The current radius of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + particle was found in the model and the information was retreived + -1 - ERROR + particle could not be found + """ + return function + + @legacy_function + def set_radius(): + """ + Set the radius of a particle. Radius is a scalar property of a + particle. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the radius of. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "radius", + dtype="float64", + direction=function.IN, + description="The new radius of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + particle was found in the model and the information was retreived + -1 - ERROR + particle could not be found + """ + return function + + @legacy_function + def get_position(): + """ + Retrieve the position vector of a particle. Position is a vector + property, this function has 3 OUT arguments. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the state from. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "x", + dtype="float64", + direction=function.OUT, + description="The current position vector of the particle", + ) + function.addParameter( + "y", + dtype="float64", + direction=function.OUT, + description="The current position vector of the particle", + ) + function.addParameter( + "z", + dtype="float64", + direction=function.OUT, + description="The current position vector of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + current value was retrieved + -1 - ERROR + particle could not be found + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def set_position(): + """ + Update the position of a particle. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle for which the state is to be updated. " + "This index must have been returned by an earlier call to " + ":meth:`new_particle`" + ), + ) + function.addParameter( + "x", + dtype="float64", + direction=function.IN, + description="The new position vector of the particle", + ) + function.addParameter( + "y", + dtype="float64", + direction=function.IN, + description="The new position vector of the particle", + ) + function.addParameter( + "z", + dtype="float64", + direction=function.IN, + description="The new position vector of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + particle was found in the model and the information was set + -1 - ERROR + particle could not be found + -2 - ERROR + code does not support updating of a particle + """ + return function + + @legacy_function + def get_velocity(): + """ + Retrieve the velocity vector of a particle. Position is a vector + property, this function has 3 OUT arguments. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the velocity from. This index " + "must have been returned by an earlier call to " + ":meth:`new_particle`" + ), + ) + function.addParameter( + "vx", + dtype="float64", + direction=function.OUT, + description=( + "The current x component of the position vector of the " "particle" + ), + ) + function.addParameter( + "vy", + dtype="float64", + direction=function.OUT, + description=( + "The current y component of the position vector of the " "particle" + ), + ) + function.addParameter( + "vz", + dtype="float64", + direction=function.OUT, + description=( + "The current z component of the position vector of the " "particle" + ), + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + current value was retrieved + -1 - ERROR + particle could not be found + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def set_velocity(): + """ + Set the velocity vector of a particle. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the state from. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "vx", + dtype="float64", + direction=function.IN, + description=( + "The current x component of the velocity vector of the " "particle" + ), + ) + function.addParameter( + "vy", + dtype="float64", + direction=function.IN, + description=( + "The current y component of the velocity vector of the " "particle" + ), + ) + function.addParameter( + "vz", + dtype="float64", + direction=function.IN, + description=( + "The current z component of the velocity vector of the " "particle" + ), + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + current value was retrieved + -1 - ERROR + particle could not be found + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def get_acceleration(): + """ + Retrieve the acceleration vector of a particle. Second time derivative + of the position. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle to get the state from. This index must " + "have been returned by an earlier call to :meth:`new_particle`" + ), + ) + function.addParameter( + "ax", + dtype="float64", + direction=function.OUT, + description="The current acceleration vector of the particle", + ) + function.addParameter( + "ay", + dtype="float64", + direction=function.OUT, + description="The current acceleration vector of the particle", + ) + function.addParameter( + "az", + dtype="float64", + direction=function.OUT, + description="The current acceleration vector of the particle", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + current value was retrieved + -1 - ERROR + particle could not be found + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def get_potential(): + """ + Retrieve the potential at a particle position, for retrieving the + potential anywhere in the field use get_potential_at_point. + """ + function = LegacyFunctionSpecification() + + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description=( + "Index of the particle for which the state is to be updated. " + "This index must have been returned by an earlier call to " + ":meth:`new_particle`" + ), + ) + function.addParameter( + "potential", + dtype="float64", + direction=function.OUT, + description="The current scalar potential...", + ) + function.result_type = "int32" + function.can_handle_array = True + function.result_doc = """ + 0 - OK + current value was retrieved + -1 - ERROR + particle could not be found + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def evolve_model(): + """ + Evolve the model until the given time, or until a stopping condition is + set. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "time", + dtype="float64", + direction=function.IN, + description=( + "Model time to evolve the code to. The model will be " + "evolved until this time is reached exactly or just after." + ), + ) + function.result_type = "int32" + return function + + @legacy_function + def commit_particles(): + """ + Let the code perform initialization actions + after all particles have been loaded in the model. + Should be called before the first evolve call and + after the last new_particle call. + """ + function = LegacyFunctionSpecification() + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Model is initialized and evolution can start + -1 - ERROR + Error happened during initialization, this error needs to be + further specified by every code implemention + """ + return function + + @legacy_function + def synchronize_model(): + """ + After an evolve the particles may be at different simulation + times. Synchronize the particles to a consistent stat + at the current simulation time + """ + function = LegacyFunctionSpecification() + function.result_type = "int32" + function.result_doc = """ + 0 - OK + + """ + return function + + @legacy_function + def recommit_particles(): + """ + Let the code perform initialization actions + after the number of particles have been updated + or particle attributes have been updated from + the script. + """ + function = LegacyFunctionSpecification() + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Model is initialized and evolution can start + -1 - ERROR + Error happened during initialization, this error needs to be + further specified by every code implemention + """ + return function + + @legacy_function + def get_eps2(): + """ + Retrieve the current value of the squared smoothing parameter. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "epsilon_squared", + dtype="float64", + direction=function.OUT, + description="The current value of the smooting parameter, squared.", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the smoothing parameter was set + -1 - ERROR + The code does not have support for a smoothing parameter + """ + return function + + @legacy_function + def set_eps2(): + """ + Update the value of the squared smoothing parameter. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "epsilon_squared", + dtype="float64", + direction=function.IN, + description="The new value of the smooting parameter, squared.", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the smoothing parameter was set + -1 - ERROR + The code does not have support for a smoothing parameter + """ + return function + + @legacy_function + def get_kinetic_energy(): + """ + Retrieve the current kinetic energy of the model + """ + function = LegacyFunctionSpecification() + function.addParameter( + "kinetic_energy", + dtype="float64", + direction=function.OUT, + description="The kinetic energy of the model", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the kinetic energy was set + -1 - ERROR + Kinetic energy could not be provided + """ + return function + + @legacy_function + def get_potential_energy(): + """ + Retrieve the current potential energy of the model + """ + function = LegacyFunctionSpecification() + function.addParameter( + "potential_energy", + dtype="float64", + direction=function.OUT, + description="The potential energy of the model", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the potential energy was set + -1 - ERROR + Kinetic potential could not be provided + """ + return function + + @legacy_function + def get_time(): + """ + Retrieve the model time. This time should be close to the end time + specified in the evolve code. Or, when a collision was detected, it + will be the model time of the collision. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "time", + dtype="float64", + direction=function.OUT, + description="The current model time", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the time was retrieved + -1 - ERROR + The code does not have support for querying the time + """ + return function + + @legacy_function + def get_begin_time(): + """ + Retrieve the model time to start the evolution at. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "time", + dtype="float64", + direction=function.OUT, + description="The begin time", + unit=nbody_system.time, + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the time was retrieved + -2 - ERROR + The code does not have support for querying the begin time + """ + return function + + @legacy_function + def set_begin_time(): + """ + Set the model time to start the evolution at. This is an offset for + all further calculations in the code. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "time", + dtype="float64", + direction=function.IN, + description="The model time to start at", + unit=nbody_system.time, + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Time value was changed + -2 - ERROR + The code does not support setting the begin time + """ + return function + + @legacy_function + def get_time_step(): + """ + Retrieve the model timestep. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "time_step", + dtype="float64", + direction=function.OUT, + description="The current model timestep", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the time step was retrieved + -1 - ERROR + The code does not have support for querying the time + """ + return function + + @legacy_function + def get_total_mass(): + """ + Retrieve the sum of the masses of all particles. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "mass", + dtype="float64", + direction=function.OUT, + description="The total mass of the model", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the kinetic mass was retrieved + -1 - ERROR + Total mass could not be provided + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def get_center_of_mass_position(): + """ + Retrieve the center of mass (a point in space) of all particles. + """ + function = LegacyFunctionSpecification() + function.can_handle_array = True + function.addParameter( + "x", + dtype="float64", + direction=function.OUT, + description="The center of mass of the model", + ) + function.addParameter( + "y", + dtype="float64", + direction=function.OUT, + description="The center of mass of the model", + ) + function.addParameter( + "z", + dtype="float64", + direction=function.OUT, + description="The center of mass of the model", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the center was retrieved + -1 - ERROR + The mass could not be provided + -2 - ERROR + not yet implemented + """ + return function + + @legacy_function + def get_center_of_mass_velocity(): + """ + Retrieve the velocity of the center of mass of all particles. This + velocity is mass weighted mean of the velocity of all particles. + """ + function = LegacyFunctionSpecification() + function.can_handle_array = True + function.addParameter( + "vx", + dtype="float64", + direction=function.OUT, + description="The mean velocity of the model", + ) + function.addParameter( + "vy", + dtype="float64", + direction=function.OUT, + description="The mean velocity of the model", + ) + function.addParameter( + "vz", + dtype="float64", + direction=function.OUT, + description="The mean velocity of the model", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the center of mass velocity was retrieved + -1 - ERROR + The value could not be provided + """ + return function + + @legacy_function + def get_total_radius(): + """ + Return the radius of the sphere, centered on the center of mass that + contains all the particles. *get_size?* + """ + function = LegacyFunctionSpecification() + function.addParameter( + "radius", + dtype="float64", + direction=function.OUT, + description=( + "The maximum distance from a star to the center of mass of the model" + ), + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Current value of the radius was retrieved + -1 - ERROR + The value could not be provided + """ + return function + + @legacy_function + def get_number_of_particles(): + """ + Retrieve the total number of particles defined in the code + """ + function = LegacyFunctionSpecification() + function.addParameter( + "number_of_particles", + dtype="int32", + direction=function.OUT, + description="Count of the particles in the code", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Count could be determined + -1 - ERROR + Unable to determine the count + """ + return function + + @legacy_function + def get_index_of_first_particle(): + """ + Retrieve the index of first particle. When this index is used as the + starting index for the ``get_index_of_next_particle`` method, all + particles can be iterated over:: + + error, first_index = instance.get_index_of_first_particle() + current_index = first_index + while error == 0: + status, mass = instance.get_mass(current_index) + print mass + error, current_index = instance.get_index_of_next_particle(current_index) + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.OUT, + description="Index of the first particle", + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Index was set + 1 - ERROR + Code has no particles, or cannot set the index + """ + return function + + @legacy_function + def get_index_of_next_particle(): + """ + Retrieve the index of the particle following the provided index. The + iteration direction is determined by the code. + """ + function = LegacyFunctionSpecification() + function.addParameter( + "index_of_the_particle", + dtype="int64", + direction=function.IN, + description="Index of the particle", + ) + function.addParameter( + "index_of_the_next_particle", + dtype="int32", + direction=function.OUT, + description=( + "Index of the particle following the particle with the " + "provided index" + ), + ) + function.result_type = "int32" + function.result_doc = """ + 0 - OK + Index was set + 1 - STATE + Last index was reached + -1 - ERROR + Particle could not be found + """ + return function + + +class GravitationalDynamics64Documentation: + + def __get__(self, instance, owner): + + string = "" + + string = instance.parameters.__doc__ + return string + + +class GravitationalDynamics64(common.CommonCode): + NBODY = object() + + __doc__ = GravitationalDynamics64Documentation() + + def __init__(self, legacy_interface, unit_converter=None, **options): + self.unit_converter = unit_converter + + common.CommonCode.__init__(self, legacy_interface, **options) + + def define_properties(self, handler): + handler.add_property("get_kinetic_energy") + handler.add_property("get_potential_energy") + handler.add_property("get_total_radius") + handler.add_property("get_center_of_mass_position") + handler.add_property("get_center_of_mass_velocity") + handler.add_property("get_total_mass") + handler.add_property("get_time", public_name="model_time") + + def define_state(self, handler): + common.CommonCode.define_state(self, handler) + handler.add_transition("END", "INITIALIZED", "initialize_code", False) + + handler.add_transition("INITIALIZED", "EDIT", "commit_parameters") + handler.add_transition( + "RUN", "CHANGE_PARAMETERS_RUN", "before_set_parameter", False + ) + handler.add_transition( + "EDIT", "CHANGE_PARAMETERS_EDIT", "before_set_parameter", False + ) + handler.add_transition( + "UPDATE", "CHANGE_PARAMETERS_UPDATE", "before_set_parameter", False + ) + handler.add_transition("CHANGE_PARAMETERS_RUN", "RUN", "recommit_parameters") + handler.add_transition("CHANGE_PARAMETERS_EDIT", "EDIT", "recommit_parameters") + handler.add_transition( + "CHANGE_PARAMETERS_UPDATE", "UPDATE", "recommit_parameters" + ) + + handler.add_method("CHANGE_PARAMETERS_RUN", "before_set_parameter") + handler.add_method("CHANGE_PARAMETERS_EDIT", "before_set_parameter") + handler.add_method("CHANGE_PARAMETERS_UPDATE", "before_set_parameter") + + handler.add_method("CHANGE_PARAMETERS_RUN", "before_get_parameter") + handler.add_method("CHANGE_PARAMETERS_EDIT", "before_get_parameter") + handler.add_method("CHANGE_PARAMETERS_UPDATE", "before_get_parameter") + handler.add_method("RUN", "before_get_parameter") + handler.add_method("EDIT", "before_get_parameter") + handler.add_method("UPDATE", "before_get_parameter") + handler.add_method("EVOLVED", "before_get_parameter") + + handler.add_method("EDIT", "new_particle") + handler.add_method("EDIT", "delete_particle") + handler.add_method("UPDATE", "new_particle") + handler.add_method("UPDATE", "delete_particle") + handler.add_transition("EDIT", "RUN", "commit_particles") + handler.add_transition("RUN", "UPDATE", "new_particle", False) + handler.add_transition("RUN", "UPDATE", "delete_particle", False) + handler.add_transition("UPDATE", "RUN", "recommit_particles") + handler.add_transition("RUN", "EVOLVED", "evolve_model", False) + handler.add_method("EVOLVED", "evolve_model") + handler.add_transition("EVOLVED", "RUN", "synchronize_model") + handler.add_method("RUN", "synchronize_model") + handler.add_method("RUN", "get_state") + handler.add_method("RUN", "get_mass") + handler.add_method("RUN", "get_position") + handler.add_method("RUN", "get_velocity") + handler.add_method("RUN", "get_potential") + handler.add_method("RUN", "get_potential_energy") + handler.add_method("RUN", "get_kinetic_energy") + handler.add_transition("RUN", "UPDATE", "set_mass", False) + handler.add_transition("RUN", "UPDATE", "set_position", False) + handler.add_transition("RUN", "UPDATE", "set_velocity", False) + handler.add_transition("RUN", "UPDATE", "set_radius", False) + handler.add_method("UPDATE", "set_mass") + handler.add_method("UPDATE", "set_position") + handler.add_method("UPDATE", "set_velocity") + handler.add_method("UPDATE", "set_radius") + + def define_parameters(self, handler): + handler.add_method_parameter( + "get_time_step", + None, + "timestep", + "constant timestep for iteration", + default_value=0.7 | nbody_system.time, + ) + + handler.add_method_parameter( + "get_begin_time", + "set_begin_time", + "begin_time", + "model time to start the simulation at", + default_value=0.0 | nbody_system.time, + ) + + def define_methods(self, handler): + common.CommonCode.define_methods(self, handler) + handler.add_method("evolve_model", (nbody_system.time,), (handler.ERROR_CODE,)) + + handler.add_method( + "new_particle", + ( + nbody_system.mass, + nbody_system.length, + nbody_system.length, + nbody_system.length, + nbody_system.speed, + nbody_system.speed, + nbody_system.speed, + nbody_system.length, + ), + ( + handler.INDEX, + handler.ERROR_CODE, + ), + ) + handler.add_method("delete_particle", (handler.NO_UNIT,), (handler.ERROR_CODE,)) + handler.add_method( + "get_state", + (handler.NO_UNIT,), + ( + nbody_system.mass, + nbody_system.length, + nbody_system.length, + nbody_system.length, + nbody_system.speed, + nbody_system.speed, + nbody_system.speed, + nbody_system.length, + handler.ERROR_CODE, + ), + ) + handler.add_method( + "set_state", + ( + handler.NO_UNIT, + nbody_system.mass, + nbody_system.length, + nbody_system.length, + nbody_system.length, + nbody_system.speed, + nbody_system.speed, + nbody_system.speed, + nbody_system.length, + ), + (handler.ERROR_CODE), + ) + handler.add_method( + "set_mass", + ( + handler.NO_UNIT, + nbody_system.mass, + ), + (handler.ERROR_CODE), + ) + handler.add_method( + "get_mass", (handler.NO_UNIT,), (nbody_system.mass, handler.ERROR_CODE) + ) + handler.add_method( + "set_radius", + ( + handler.NO_UNIT, + nbody_system.length, + ), + (handler.ERROR_CODE), + ) + handler.add_method( + "get_radius", (handler.NO_UNIT,), (nbody_system.length, handler.ERROR_CODE) + ) + handler.add_method( + "set_position", + ( + handler.NO_UNIT, + nbody_system.length, + nbody_system.length, + nbody_system.length, + ), + (handler.ERROR_CODE), + ) + handler.add_method( + "get_position", + (handler.NO_UNIT,), + ( + nbody_system.length, + nbody_system.length, + nbody_system.length, + handler.ERROR_CODE, + ), + ) + handler.add_method( + "set_velocity", + ( + handler.NO_UNIT, + nbody_system.speed, + nbody_system.speed, + nbody_system.speed, + ), + (handler.ERROR_CODE), + ) + handler.add_method( + "get_velocity", + (handler.NO_UNIT,), + ( + nbody_system.speed, + nbody_system.speed, + nbody_system.speed, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_acceleration", + (handler.NO_UNIT,), + ( + nbody_system.acceleration, + nbody_system.acceleration, + nbody_system.acceleration, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_potential", + (handler.NO_UNIT,), + ( + nbody_system.length**2 * nbody_system.time**-2, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_indices_of_colliding_particles", + (), + ( + handler.NO_UNIT, + handler.NO_UNIT, + handler.ERROR_CODE, + ), + ) + + handler.add_method("commit_particles", (), (handler.ERROR_CODE)) + + handler.add_method("recommit_particles", (), (handler.ERROR_CODE)) + + handler.add_method("synchronize_model", (), (handler.ERROR_CODE)) + + handler.add_method( + "get_time_step", + (), + ( + nbody_system.time, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_kinetic_energy", + (), + ( + nbody_system.mass * nbody_system.length**2 * nbody_system.time**-2, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_potential_energy", + (), + ( + nbody_system.mass * nbody_system.length**2 * nbody_system.time**-2, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_total_radius", + (), + ( + nbody_system.length, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_center_of_mass_position", + (), + ( + nbody_system.length, + nbody_system.length, + nbody_system.length, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_center_of_mass_velocity", + (), + ( + nbody_system.length / nbody_system.time, + nbody_system.length / nbody_system.time, + nbody_system.length / nbody_system.time, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_total_mass", + (), + ( + nbody_system.mass, + handler.ERROR_CODE, + ), + ) + + handler.add_method( + "get_time", + (), + ( + nbody_system.time, + handler.ERROR_CODE, + ), + ) + + def define_particle_sets(self, handler): + handler.define_set("particles", "index_of_the_particle") + handler.set_new("particles", "new_particle") + handler.set_delete("particles", "delete_particle") + handler.add_setter("particles", "set_state") + handler.add_getter("particles", "get_state") + handler.add_setter("particles", "set_mass") + handler.add_getter("particles", "get_mass", names=("mass",)) + handler.add_setter("particles", "set_position") + handler.add_getter("particles", "get_position") + handler.add_setter("particles", "set_velocity") + handler.add_getter("particles", "get_velocity") + handler.add_setter("particles", "set_radius") + handler.add_getter("particles", "get_radius") + handler.add_query( + "particles", + "get_indices_of_colliding_particles", + public_name="select_colliding_particles", + ) + + def get_colliding_particles(self): + subset = self.colliding_particles_method._run(self, self.particles) + return subset + + def define_converter(self, handler): + if self.unit_converter is not None: + handler.set_converter(self.unit_converter.as_converter_from_si_to_generic()) + + def commit_parameters(self): + self.parameters.send_not_set_parameters_to_code() + self.parameters.send_cached_parameters_to_code() + self.overridden().commit_parameters() + + def cleanup_code(self): + self.overridden().cleanup_code() + + handler = self.get_handler("PARTICLES") + handler._cleanup_instances() + + def reset(self): + parameters = self.parameters.copy() + self.cleanup_code() + self.initialize_code() + self.parameters.reset_from_memento(parameters) + + def get_total_energy(self): + return self.get_potential_energy() + self.get_kinetic_energy() diff --git a/src/amuse/community/interface/gd/gravity_field.py b/src/amuse/community/interface/gd/gravity_field.py new file mode 100644 index 0000000000..9838148284 --- /dev/null +++ b/src/amuse/community/interface/gd/gravity_field.py @@ -0,0 +1,113 @@ +""" +Stellar Dynamics Interface Definition +""" + +from amuse.units import nbody_system + +from amuse.rfi.core import legacy_function +from amuse.rfi.core import LegacyFunctionSpecification + + +class SinglePointGravityFieldInterface: + """ + Codes implementing the gravity field interface provide functions to + calculate the force and potential energy fields at any point. + """ + + @legacy_function + def get_gravity_at_point(): + """ + Get the gravitational acceleration at the given points. To calculate + the force on bodies at those points, multiply with the mass of the + bodies + """ + function = LegacyFunctionSpecification() + for x in ["eps", "x", "y", "z"]: + function.addParameter( + x, dtype="float64", direction=function.IN, unit=nbody_system.length + ) + for x in ["ax", "ay", "az"]: + function.addParameter( + x, + dtype="float64", + direction=function.OUT, + unit=nbody_system.acceleration, + ) + function.result_type = "int32" + function.can_handle_array = True + return function + + @legacy_function + def get_potential_at_point(): + """ + Determine the gravitational potential on any given point + """ + function = LegacyFunctionSpecification() + for x in ["eps", "x", "y", "z"]: + function.addParameter( + x, dtype="float64", direction=function.IN, unit=nbody_system.length + ) + for x in ["phi"]: + function.addParameter( + x, dtype="float64", direction=function.OUT, unit=nbody_system.potential + ) + function.result_type = "int32" + function.can_handle_array = True + return function + + +class GravityFieldInterface: + """ + Codes implementing the gravity field interface provide functions to + calculate the force and potential energy fields at any point. + """ + + @legacy_function + def get_gravity_at_point(): + """ + Get the gravitational acceleration at the given points. To calculate + the force on bodies at those points, multiply with the mass of the + bodies + """ + function = LegacyFunctionSpecification() + for x in ["eps", "x", "y", "z"]: + function.addParameter( + x, dtype="float64", direction=function.IN, unit=nbody_system.length + ) + for x in ["ax", "ay", "az"]: + function.addParameter( + x, + dtype="float64", + direction=function.OUT, + unit=nbody_system.acceleration, + ) + function.addParameter("npoints", dtype="i", direction=function.LENGTH) + function.result_type = "int32" + function.must_handle_array = True + return function + + @legacy_function + def get_potential_at_point(): + """ + Determine the gravitational potential on any given point + """ + function = LegacyFunctionSpecification() + for x in ["eps", "x", "y", "z"]: + function.addParameter( + x, dtype="float64", direction=function.IN, unit=nbody_system.length + ) + for x in ["phi"]: + function.addParameter( + x, dtype="float64", direction=function.OUT, unit=nbody_system.potential + ) + function.addParameter("npoints", dtype="i", direction=function.LENGTH) + function.result_type = "int32" + function.must_handle_array = True + return function + + +class GravityFieldCode: + + def define_state(self, handler): + handler.add_method("RUN", "get_gravity_at_point") + handler.add_method("RUN", "get_potential_at_point")