diff --git a/mrdna/readers/segmentmodel_from_oxdna.py b/mrdna/readers/segmentmodel_from_oxdna.py
new file mode 100644
index 0000000000000000000000000000000000000000..63ffa7625d301c990cf76da8085e2f2f2ad788a2
--- /dev/null
+++ b/mrdna/readers/segmentmodel_from_oxdna.py
@@ -0,0 +1,145 @@
+from mrdna import logger, devlogger
+from .segmentmodel_from_lists import model_from_basepair_stack_3prime
+from ..arbdmodel.coords import rotationAboutAxis
+
+import numpy as np
+from scipy.spatial import distance_matrix
+
+_seq_to_int_dict = dict(A=0,T=1,C=2,G=3)
+_seq_to_int_dict = {k:str(v) for k,v in _seq_to_int_dict.items()}
+
+_yrot = rotationAboutAxis(axis=(0,1,0), angle=180).dot(rotationAboutAxis(axis=(0,0,1),angle=-40))
+
+def mrdna_model_from_oxdna(coordinate_file, topology_file, **model_parameters):
+    """ Construct an mrdna model from oxDNA coordinate and topology files """
+
+    top_data = np.loadtxt(topology_file, skiprows=1,
+                          unpack=True,
+                          dtype=np.dtype('i4,U1,i4,i4')
+                          )
+    conf_data = np.loadtxt(coordinate_file, skiprows=3)
+
+    ## Reverse direction so indices run 5'-to-3'
+    top_data = [a[::-1] for a in top_data]
+    conf_data = conf_data[::-1,:]
+
+    r = conf_data[:,:3] * 8.518
+    base_dir = conf_data[:,3:6]
+    # basepair_pos = r + base_dir*6.0
+    basepair_pos = r + base_dir*10.0
+    normal_dir = -conf_data[:,6:9]
+    perp_dir = np.cross(base_dir, normal_dir)
+    orientation = np.array([np.array(o).T.dot(_yrot) for o in zip(perp_dir,-base_dir,-normal_dir)])
+    
+    def _get_bp(sequence=None):
+        dists = distance_matrix(r,basepair_pos) + np.eye(len(r))*1000
+        dists = 0.5*(dists + dists.T)
+        
+        bp = np.array([np.argmin(da) for da in dists])
+
+        for i,j in enumerate(bp):
+            if j == -1: continue
+            # devlogger.info(f'bp {i} {j} {dists[i,j]}')
+            if dists[i,j] > 2:
+                bp[i] = -1
+            elif bp[j] != i:
+                bpj = bp[j]
+                logger.warning( " ".join([str(_x) for _x in ["Bad pair", i, j, bp[i], bp[j], dists[i,j], dists[j,i], dists[bpj,j], dists[j,bpj]]]) )
+
+        for i,j in enumerate(bp):
+            if j == -1: continue
+            if bp[j] != i:
+                bpj = bp[j]
+                logger.warning( " ".join([str(_x) for _x in ["Bad pair2", i, j, bp[i], bp[j], dists[i,j], dists[j,i], dists[bpj,j], dists[j,bpj]]]) )
+                raise Exception
+
+        if sequence is not None:
+            seq = sequence
+            bp_seq = sequence[bp]
+            bp_seq[bp==-1] = 'X'
+            bad_bps = np.where( (bp >= 0) &
+                                (((seq == 'C') & (bp_seq != 'G')) |
+                                 ((seq == 'G') & (bp_seq != 'C')) |
+                                 ((seq == 'T') & (bp_seq != 'A')) | 
+                                 ((seq == 'U') & (bp_seq != 'A')) |
+                                 ((seq == 'A') & ((bp_seq != 'T') | (bp_seq != 'U')))
+                                 ) )[0]
+            bp[bp[bad_bps]] = -1
+            bp[bad_bps] = -1
+            
+        return bp
+
+    def _get_stack():
+        dists = distance_matrix( r + 3.5*normal_dir + 2.1*perp_dir -1*base_dir, r ) + np.eye(len(r))*1000
+        stack = np.array([np.argmin(da) for da in dists])
+        for i,j in enumerate(stack):
+            if dists[i,j] > 8:
+                stack[i] = -1
+            elif i < 10:
+                ## development info
+                # devlogger.info([i,j,dists[i,j]])
+                # dr = r[j] - (r[i] - normal_dir[i]*3.4 + perp_dir[i]*1 + base_dir[i]*1)
+                dr = r[j] - r[i]
+                # devlogger.info([normal_dir[i].dot(dr), perp_dir[i].dot(dr), base_dir[i].dot(dr)])
+        return np.array(stack)
+
+    seq = top_data[1]
+    bp = _get_bp(seq)
+    stack = _get_stack()
+      
+    three_prime = len(r) - top_data[2] -1
+    five_prime = len(r) - top_data[3] -1
+    three_prime[three_prime >= len(r)] = -1
+    five_prime[five_prime >= len(r)] = -1
+
+    def _debug_write_bonds():
+        from ..arbdmodel import ParticleType, PointParticle, ArbdModel, Group
+        bond = tuple()
+        b_t = ParticleType('BASE')
+        p_t = ParticleType('PHOS')
+
+        parts = []
+        for i,(r0,r_bp,three_prime0,bp0,stack0,seq0) in enumerate(zip(r,basepair_pos, three_prime, bp, stack, seq)):
+            p = PointParticle(p_t, name='PHOS', position = r0, resid=i)
+            b = PointParticle(b_t, name=seq0, position = 0.5*(r0+r_bp), resid=i)
+            parts.extend((p,b))
+
+        model = ArbdModel(parts)
+        model.writePdb('test.pdb')
+
+        for i,(r0,r_bp,three_prime0,bp0,stack0) in enumerate(zip(r,basepair_pos, three_prime, bp, stack)):
+            model.add_bond(parts[2*i],parts[2*i+1],bond)
+            j = three_prime0
+            if j >= 0:
+                model.add_bond(parts[2*i],parts[2*j],bond)
+            j = bp0
+            if j >= 0:
+                model.add_bond(parts[2*i+1],parts[2*j+1],bond)
+        model.writePsf('test.psf')
+
+        model.bonds = []
+        for i,(r0,r_bp,three_prime0,bp0,stack0) in enumerate(zip(r,basepair_pos, three_prime, bp, stack)):
+            j = stack0
+            if j >= 0:
+                model.add_bond(parts[2*i],parts[2*j],bond)
+        model.writePsf('test.stack.psf')
+    ## _debug_write_bonds()
+
+    logger.info(f'mrdna_model_from_oxdna: num_bp, num_ss_nt, num_stacked: {np.sum(bp>=0)//2} {np.sum(bp<0)} {np.sum(stack >= 0)}')
+    
+    model = model_from_basepair_stack_3prime( r, bp, stack, three_prime, seq, orientation, **model_parameters )
+
+    """
+    model.DEBUG = True
+    model.generate_bead_model(1,1,False,True,one_bead_per_monomer=True)
+    for seg in model.segments:
+        for bead in seg.beads:
+            bead.position = bead.position + np.random.standard_normal(3)
+    
+    simulate( model, output_name='test', directory='test4' )
+    """
+    return model
+
+if __name__ == "__main__":
+    mrdna_model_from_oxdna("0-from-collab/nanopore.oxdna","0-from-collab/nanopore.top")
+    # mrdna_model_from_oxdna("2-oxdna.manual/output/from_mrdna-oxdna-min.last.conf","0-from-collab/nanopore.top")