narupa.app.client module

Module containing a basic interactive molecular dynamics client that receives frames and can publish interactions.

class narupa.app.client.NarupaImdClient(*, trajectory_address: Tuple[str, int] = None, imd_address: Tuple[str, int] = None, multiplayer_address: Tuple[str, int] = None, max_frames=50, all_frames: Optional[bool] = None)

Bases: object

Interactive molecular dynamics client that receives frames, create selections, and join the multiplayer shared state.

Parameters:
  • trajectory_address – Address and port of the trajectory service.
  • imd_address – Address and port of the iMD service.
  • multiplayer_address – Address and port of the multiplayer service.
  • max_frames – Maximum number of frames to store in a buffer, if not storing all frames.

All addresses are optional, so one can, for example, just connect to a trajectory service to passively receive frames.

The :fun:`NarupaImdClient.autoconnect` and :fun:`NarupaImdClient.connect_to_single_server` methods provide shorthands for common server setups.

The Narupa Imd client can be used to inspect frames received from a narupa.trajectory.FrameServer, which can be useful for analysis.

One of the main uses of the client is to create selections that control how a group of particles will be visualised and interacted with in other clients (e.g., the VR client):

# Connect to the multiplayer
client.subscribe_multiplayer()
# Create a selection called 'Selection' which selects particles with indices 0-4
selection = client.create_selection("Selection", [0, 1, 2, 3, 4])

Selections are created and updated based on lists of particle indices. Tools such as MDAnalysis or MDTraj <http://mdtraj.org/>_ are very good at extracting indices of particles based on a human readable command.

With a selection in hand, the way in which it is rendered and interacted with can be changed and transmitted to other clients (i.e. VR) using the modify context:

# Change how the selection is rendered and interacted with.
with selection.modify():
    selection.renderer = {
            'color': 'IndianRed',
            'scale': 0.1,
            'render': 'liquorice'
        }
    selection.velocity_reset = True  # Reset the velocities after interacting.
    selection.interaction_method = 'group'  # Interact with the selection as a group.
all_frames
are_frames_subscribed

Returns True if the client is subscribed to frames with either subscribe_to_all_frames() or subscribe_to_frames().

attempt_update_multiplayer_locks(update: Dict[str, Optional[float]]) → bool

Attempt to acquire and/or free a number of locks on the shared state. :param update: A dictionary of keys to either a duration in

seconds to attempt to acquire or renew a lock, or None to indicate the lock should be released if held.
Returns:True if the desired locks were acquired, and False otherwise.
attempt_update_multiplayer_state(update: narupa.utilities.change_buffers.DictionaryChange) → bool

Attempt to make a single atomic change to the shared state, blocking until a response is received. :param update: A single change to make to the shared state that will

either be made in full, or ignored if some of the keys are locked by another user.
Returns:True if the server accepted our change, and False otherwise.
classmethod autoconnect(search_time=2.0, discovery_address: Optional[str] = None, discovery_port: Optional[int] = None, name: Optional[str] = None)

Autoconnect to the first available server discovered that at least produces frames.

Parameters:
  • search_time – Time, in seconds, to search for.
  • discovery_address – IP address to search on.
  • discovery_port – Port upon which to listen for discovery messages.
  • name – If supplied, only servers with this name will be used.
Returns:

Instantiation of an iMD client connected to whatever is available at the first

clear_selections()

Remove all selections in the system

close(clear_frames=True)

Closes the connection with the server.

Parameters:clear_frames – Whether to clear the frames received by the client, or keep them.
connect(*, trajectory_address: Tuple[str, int] = None, imd_address: Tuple[str, int] = None, multiplayer_address: Tuple[str, int] = None)

Connects the client to all services for which addresses are provided.

connect_imd(address: Tuple[str, int])

Connects the client to the given interactive molecular dynamics server, allowing it to start publishing interactions.

Parameters:
  • address – The address and port of the IMD server.
  • port – The port of the IMD server.
connect_multiplayer(address: Tuple[str, int])

Connects the client to the given multiplayer server.

Parameters:address – The address and port of the multiplayer server.
classmethod connect_to_single_server(address: Optional[str] = None, port: Optional[int] = None)

Connect to a single Narupa server running all services on the same port.

Parameters:
  • address – Address of the server.
  • port – Server port
Returns:

Instantiation of a client connected to all available services on the server at the given destination.

classmethod connect_to_single_server_multiple_ports(address: str, trajectory_port: int, imd_port: int, multiplayer_port: int)

Connect to a collection of Narupa servers running at the same address but potentially different ports.

Parameters:
  • address – Address of the server.
  • multiplayer_port – The port at which multiplayer is running.
  • trajectory_port – The port at which the trajectory service is running.
  • imd_port – The port at which the iMD service is running.
Returns:

Instantiation of a client connected to all available services on the server at the given destination.

connect_trajectory(address: Tuple[str, int])

Connects the client to the given trajectory server, and begin receiving frames.

Parameters:address – The address and port of the trajectory server.
create_selection(name: str, particle_ids: Optional[Iterable[int]] = None) → narupa.app.selection.RenderingSelection

Create a particle selection with the given name.

Parameters:
  • name – The user-friendly name of the selection.
  • particle_ids – The indices of the particles to include in the selection.
Returns:

The selection that was created.

current_frame

A copy of the current state of the trajectory, formed by collating all received frames.

Returns:FrameData, which is empty if none have been received.
first_frame

The first received trajectory frame, if any.

Returns:The first frame received by this trajectory, or None.
frames

The most recently received frames up to the storage limit specified by max_frames.

Returns:Sequence of frames.
get_selection(selection_id: str) → narupa.app.selection.RenderingSelection

Get the selection with the given selection id, throwing a KeyError if it is not present. For the root selection, use the root_selection property.

Parameters:selection_id – The id of the selection
Returns:The selection if it is present
get_shared_value(key)

Attempts to retrieve the value for the given key in the multiplayer shared value store.

Parameters:key – The key that identifies the value
Returns:The value stored in the dictionary
Raises:grpc._channel._Rendezvous – When not connected to a multiplayer service
interactions

The dictionary of current interactions received by this client. :return: Dictionary of active interactions, keyed by interaction ID identifying who is performing the interactions.

latest_frame

The trajectory frame most recently received, if any.

Returns:FrameData, or None if none has been received.
latest_multiplayer_values

The latest state of the multiplayer shared key/value store.

Returns:Dictionary of the current state of multiplayer shared key/value store.
remove_selection(selection: narupa.app.selection.RenderingSelection)

Delete the given selection

remove_shared_value(key: str) → bool

Attempts to remove the given key on the multiplayer shared value store.

Raises:grpc._channel._Rendezvous – When not connected to a multiplayer service
root_selection

Get the root selection, creating it if it does not exist yet.

Returns:The selection representing the root selection of the system
run_command(name, **args)

Runs a command on the trajectory service, multiplayer service or imd service as appropriate.

Parameters:
  • name – Name of the command to run
  • args – Dictionary of arguments to run with the command.
Returns:

Results of the command, if any.

run_imd_command(name: str, **args) → Dict[str, object]

Runs a command on the iMD service.

Parameters:
  • name – Name of the command to run
  • args – Dictionary of arguments to run with the command.
Returns:

Results of the command, if any.

run_multiplayer_command(name: str, **args)

Runs a command on the multiplayer service.

Parameters:
  • name – Name of the command to run.
  • args – Dictionary of arguments to run with the command.
Returns:

Results of the command, if any.

run_pause()

Sends a request to pause the simulation to the trajectory service.

run_play()

Sends a request to start playing the trajectory to the trajectory service.

run_reset()

Sends a request to reset the simulation to the trajectory service.

run_step()

Sends a request to take one step to the trajectory service.

run_trajectory_command(name: str, **args) → Dict[str, object]

Runs a command on the trajectory service.

Parameters:
  • name – Name of the command to run
  • args – Dictionary of arguments to run with the command.
Returns:

Results of the command, if any.

selections

Get all selections which are stored in the shared key store.

Returns:An iterable of all the selections stored in the shared key store.
set_shared_value(key, value) → bool

Attempts to set the given key/value pair on the multiplayer shared value store.

Parameters:
  • key – The key that identifies the value to be stored.
  • value – The new value to store.
Returns:

True if successful, False otherwise.

Raises:

grpc._channel._Rendezvous – When not connected to a multiplayer service

start_interaction(interaction: Optional[narupa.imd.particle_interaction.ParticleInteraction] = None) → str

Start an interaction with the IMD server.

Parameters:interaction – An optional :class: ParticleInteraction with which to begin.
Returns:The unique interaction ID of this interaction, which can be used to update the interaction with update_interaction().
Raises:ValueError, if the there is no IMD connection available.
stop_interaction(interaction_id) → bool

Stops the interaction identified with the given interaction_id on the server. This method blocks until the server returns a reply indicating that the interaction has stopped.

Parameters:interaction_id – The unique interaction ID, created with start_interaction(), that identifies the interaction to stop.
Returns:An InteractionEndReply, which is an empty message indicating

successful termination of the interaction.

Raises:
  • ValueError – if the there is no IMD connection available, or if invalid parameters are passed to the server.
  • KeyError – if the given interaction ID does not exist.
subscribe_multiplayer(interval=0.03333333333333333)

Subscribe to all multiplayer state updates.

Parameters:interval – Subscription interval for state updates.
Raises:grpc._channel._Rendezvous – When not connected to a multiplayer service
subscribe_to_all_frames()

Request all the frames from the server.

This makes the frames available with the frames, current_frame, latest_frames, and first_frame attributes.

All the frames produced by the frame server are sent from the time of the subscription get received by the client. Note that, depending on the server set up, this may not be all the frames generated by the MD engine. Subscribing to all frames is usefull for some applications such as saving a trajectory or analyses, however it may get behind the server if the frames are not received and treated as fast as they are sent.

Warning

A client can subscribe to frames only ones and cannot change how it subscribes.

subscribe_to_frames(interval: float = 0.03333333333333333)

Request the latest frames at a given time interval.

This makes the frames available with the frames, current_frame, latest_frames, and first_frame attributes.

This requests for the server to send the latest available frame at a given framerate expressed with the interval of time between two consecutive frames. This requested interval is the a minimum interval: if the frames are produced slower, then they will be sent as fast as possible.

This is usefull for applications that do not need all the frames but only the latest available ones.

Warning

A client can subscribe to frames only ones and cannot change how it subscribes.

Parameters:interval – Minimum time, in seconds, between two consecutive frames.
update_available_commands() → MutableMapping[str, narupa.command.command_info.CommandInfo]

Fetches an updated set of available commands from the services this client is connected to.

Returns:A collection of CommandInfo, detailing the commands available.

If the same command name is available on multiple services, the nested nature of the returned ChainMap will enable the user to determine the correct one to call.

update_interaction(interaction_id, interaction: narupa.imd.particle_interaction.ParticleInteraction)

Updates the interaction identified with the given interaction_id on the server with parameters from the given interaction.

Parameters:
  • interaction_id – The unique id of the interaction to be updated.
  • interaction – The :class: ParticleInteraction providing new parameters for the interaction.
Raises:

ValueError, if the there is no IMD connection available, or if invalid parameters are passed to the server.

Raises:

KeyError – if the given interaction ID does not exist.

update_selection(selection: narupa.app.selection.RenderingSelection)

Applies changes to the given selection to the shared key store.

Parameters:selection – The selection to update.
wait_until_first_frame(check_interval=0.01, timeout=1)

Wait until the first frame is received from the server.

Parameters:
  • check_interval – Interval at which to check if a frame has been received.
  • timeout – Timeout after which to stop waiting for a frame.
Returns:

The first FrameData received.

Raises:

Exception – if no frame is received.

narupa.app.client.need_frames(func, *, name: str = 'trajectory', attr: str = '_frame_client')
narupa.app.client.need_imd(func, *, name: str = 'imd', attr: str = '_imd_client')
narupa.app.client.need_multiplayer(func, *, name: str = 'multiplayer', attr: str = '_multiplayer_client')
narupa.app.client.need_trajectory_joined(func)