Oxpy

Oxpy is a Python3 library that makes it possible to use oxDNA from Python.

An example of a simple simulation

The following snippet imports the oxpy module, initialises the simulation machinery, runs a short simulation using the input file input, changes the temperature, runs more simulations steps and computes the average position of the final configuration:

import numpy as np
import oxpy

with oxpy.Context():
	# init the manager with the given input file
	manager = oxpy.OxpyManager("input")
	
	# run 1k steps
	manager.run(1000)
	
	# change the temperature
	manager.update_temperature(0.11)
	
	# run 1k steps more
	manager.run(1000)
	
	# do some computation with the current configuration
	particles = manager.config_info().particles()
	
	# compute the average position of the particles' backbones
	avg_pos = np.average(list(map(lambda p: p.backbone_site(), particles)), axis=0)
	print("Average final position:", avg_pos)
	
	# and the interaction energy between the first two particles
	print("Interaction energy between particle 0 and particle 1:", manager.config_info().interaction.pair_interaction(particles[0], particles[1]))

Warning

There is a known issue that makes the code segfault whenever multiple with oxpy.Context() are used in a single script. In these cases a simple workaround is to add a del manager instruction at the end of the with code block, like this:

for _ in range(N_sims):
   with oxpy.Context():
      manager = oxpy.OxpyManager("input")
      manager.run(N_steps)
      del manager # <-- if you comment this line the script will segfault

If you want, you can initialise the input file yourself and change some of the options before initialising the manager:

my_input = oxpy.InputFile()
my_input.init_from_filename("input")
my_input["backend"] = "CUDA"
my_input["steps"] = "1e9"
manager = oxpy.OxpyManager(my_input)

You can also use oxpy.utils.generate_default_input() to generate the following basic input file:

backend = CPU
sim_type = MD

verlet_skin = 0.2
dt = 0.001

T = 0.1

steps = 10000
print_energy_every = 1000
print_conf_interval = 100000
restart_step_counter = yes
refresh_vel = true
time_scale = linear

topology = topology.top
conf_file = init_conf.dat
trajectory_file = trajectory.dat
energy_file = energy.dat

An example of a simple analysis

Here we loop over all the configurations stored in an oxDNA trajectory file, printing the position of the first particle.

import numpy as np
import oxpy

with oxpy.Context():
    inp = oxpy.InputFile()
    inp.init_from_filename("input")
    # this object will make it possible to access the trajectory data
    backend = oxpy.analysis.AnalysisBackend(inp)

    # loop over all the configurations stored in the trajectory file
    while backend.read_next_configuration():
        # you can access the particles' details from BaseParticle instances
        print(backend.particles[0].pos)
        # or from the flattened_conf object, which exposes the simulation data as vectors that can be converted to numpy arrays
        numpy_positions = np.array(backend.flattened_conf.positions, copy=False)
        print(numpy_positions[0])

Library API

Exceptions

The oxDNA code raises oxDNAExceptions when the simulation cannot be correctly initialised or when it incurs in an unrecoverable error. These exceptions are automatically translated into Python exceptions of type oxpy.core.OxDNAError, which can then be handled in a regular try except block.

Extending Oxpy