diff --git a/arbdmodel/onck_polymer_model.py b/arbdmodel/onck_polymer_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..c15c9de3c699d808b0dfa08ac1cabddb64d1fd75
--- /dev/null
+++ b/arbdmodel/onck_polymer_model.py
@@ -0,0 +1,327 @@
+# -*- coding: utf-8 -*-
+## Test with `python -m arbdmodel.onck_polymer_model`
+
+import numpy as np
+import sys
+
+
+## Local imports
+from . import ArbdModel, ParticleType, PointParticle, Group, get_resource_path    
+from .abstract_polymer import PolymerSection, AbstractPolymerGroup
+from .interactions import NonbondedScheme, HarmonicBond, HarmonicAngle, HarmonicDihedral
+from .coords import quaternion_to_matrix
+
+"""Define particle types"""
+_types = dict(
+    A = ParticleType("ALA",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.7,
+                     lambda_ = 0.72973,
+                 ),
+    R = ParticleType("ARG",
+                     mass = 120,
+                     charge = 1,
+                     epsilon = 0.0,
+                     lambda_ = 0.0,
+                 ),
+    N = ParticleType("ASN",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.33,
+                     lambda_ = 0.432432,
+                 ),
+    D = ParticleType("ASP",
+                     mass = 120,
+                     charge = -1,
+                     epsilon = 0.0005,
+                 ),
+    C = ParticleType("CYS",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.68,
+                 ),
+    Q = ParticleType("GLN",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.64,
+                 ),
+    E = ParticleType("GLU",
+                     mass = 120,
+                     charge = -1,
+                     epsilon = 0.0005,
+                 ),
+    G = ParticleType("GLY",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.41,
+                 ),
+    H = ParticleType("HIS",
+                     mass = 120,
+                     charge = 0.0,
+                     epsilon = 0.53,
+                 ),
+    I = ParticleType("ILE",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.98,
+                 ),
+    L = ParticleType("LUE",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 1.0,
+                 ),
+    K = ParticleType("LYS",
+                     mass = 120,
+                     charge = 1,
+                     epsilon = 0.0005,
+                 ),
+    M = ParticleType("MET",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.78,
+                 ),
+    F = ParticleType("PHE",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 1.0,
+                 ),
+    P = ParticleType("PRO",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.65,
+                 ),
+    S = ParticleType("SER",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.45,
+                 ),
+    T = ParticleType("THR",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.51,
+                 ),
+    W = ParticleType("TRP",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.96,
+                 ),
+    Y = ParticleType("TYR",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.82,
+                 ),
+    V = ParticleType("VAL",
+                     mass = 120,
+                     charge = 0,
+                     epsilon = 0.94,
+                 )
+)
+for k,t in _types.items():
+    t.resname = t.name
+
+class OnckNonbonded(NonbondedScheme):
+    def __init__(self, debye_length=10, resolution=0.1, rMin=0):
+        NonbondedScheme.__init__(self, typesA=None, typesB=None,
+                                 resolution=resolution, rMin=rMin)
+        self.debye_length = debye_length
+        self.maxForce = 50
+        # self.maxForce = 100
+        # self.maxForce = None
+
+    def potential(self, r, typeA, typeB):
+        """ Electrostatics """
+        ld = self.debye_length
+        q1 = typeA.charge
+        q2 = typeB.charge
+        D = 80                  # dielectric of water
+        _z = 2.5
+        D = 80 * (1- (r/_z)**2 * np.exp(r/_z)/(np.exp(r/_z)-1)**2)
+        ## units "e**2 / (4 * pi * epsilon0 AA)" kcal_mol
+        A =  332.06371
+        u_elec = (A*q1*q2/D)*np.exp(-r/ld) / r
+
+        """ LJ-type term """
+        alpha = 0.27
+        epsilon_hp = 3.1070746 # units "13 kJ/N_A" kcal_mol
+        epsilon_rep = 2.3900574 # units "10 kJ/N_A" kcal_mol
+
+        sigma = 6.0
+        epsilon = epsilon_hp*np.sqrt( (typeA.epsilon*typeB.epsilon)**alpha )
+
+        r6 = (sigma/r)**6
+        r8 = (sigma/r)**8
+        u_lj = (epsilon_rep-epsilon) * r8
+        s = r<=sigma
+        u_lj[s] = epsilon_rep*r8[s] - epsilon*(4*r6[s]-1)/3
+        u_lj[r>25] = 0
+
+
+        u = u_elec + u_lj
+        u[0] = u[1]             # Remove NaN
+
+        maxForce = self.maxForce
+        if maxForce is not None:
+            assert(maxForce > 0)
+            f = np.diff(u)/np.diff(r)
+            f[f>maxForce] = maxForce
+            f[f<-maxForce] = -maxForce
+            u[0] = 0
+            u[1:] = np.cumsum(f*np.diff(r))
+
+        u = u-u[-1]
+
+        return u
+
+class OnckBeadsFromPolymer(Group):
+    """ units "8038 kJ / (N_A nm**2)" "0.5 * kcal_mol/AA**2" """
+    peptide_bond = HarmonicBond(k = 38.422562,
+                        r0 = 3.8,
+                        rRange = (0,500),
+                        resolution = 0.01,
+                        maxForce = 10)
+
+    def __init__(self, polymer, sequence=None, **kwargs):
+
+        if sequence is None:
+            raise NotImplementedError
+            # ... set random sequence
+
+        self.polymer = polymer
+        self.sequence = sequence
+
+        for prop in ('segname','chain'):
+            if prop not in kwargs:
+                # import pdb
+                # pdb.set_trace()
+                try:
+                    self.__dict__[prop] = polymer.__dict__[prop]
+                except:
+                    pass
+
+        if len(sequence) != polymer.num_monomers:
+            raise ValueError("Length of sequence does not match length of polymer")
+        Group.__init__(self, **kwargs)
+        
+    def _clear_beads(self):
+        ...
+        
+    def _generate_beads(self):
+        for i in range(self.polymer.num_monomers):
+            c = self.polymer.monomer_index_to_contour(i)
+            r = self.polymer.contour_to_position(c)
+            s = self.sequence[i]
+
+            bead = PointParticle(_types[s], r,
+                                 name = s,
+                                 resid = i+1)
+            self.add(bead)
+
+        ## Two consecutive monomers 
+        for i in range(len(self.children)-1):
+            b1,b2 = [self.children[i+j] for j in range(2)]
+            bond = OnckBeadsFromPolymer.peptide_bond
+            self.add_bond( i=b1, j=b2, bond = bond, exclude=True )
+
+        def bead_to_type(bead):
+            if bead.type_.name == 'PRO':
+                return 'P'
+            elif bead.type_.name == 'GLY':
+                return 'G'
+            else:
+                return 'X'
+
+        ## Three consecutive monomers 
+        for i in range(len(self.children)-2):
+            b1,b2,b3 = [self.children[i+j] for j in range(3)]
+            t1,t2,t3 = ([bead_to_type(b) for b in (b1,b2,b3)])
+
+            filename = 'onck_model_potentials/bend_O{}{}.txt'.format(
+                t2,'P' if t3 == 'P' else 'Y' )
+            self.add_angle( i=b1, j=b2, k=b3, 
+                          angle = get_resource_path(filename) )
+            self.add_exclusion( i=b1, j=b3 )
+
+        ## Four consecutive monomers 
+        for i in range(len(self.children)-3):
+            b1,b2,b3,b4 = [self.children[i+j] for j in range(4)]
+            t1,t2,t3,t4 = ([bead_to_type(b) for b in (b1,b2,b3,b4)])
+
+            filename = 'onck_model_potentials/dih_{}{}.txt'.format(t2,t3)
+            self.add_dihedral( i=b1, j=b2, k=b3, l=b4,
+                               dihedral = get_resource_path(filename) )
+            self.add_exclusion( i=b1, j=b4 )
+
+class OnckModel(ArbdModel):
+    def __init__(self, polymers,
+                 sequences = None,
+                 debye_length = 10,
+                 damping_coefficient = 50e3,
+                 DEBUG=False,
+                 **kwargs):
+
+        """ 
+        [debye_length]: angstroms
+        [damping_coefficient]: ns
+        """
+        if debye_length != 10:
+            print("""WARNING: you are deviated from the model published by Onck by choosing a debye length != 1 nm.
+    Be advised that the non-bonded cutoff is simply set to 5 * debye_length, but this is not necessarily prescribed by the model.""")
+        kwargs['timestep'] = 20e-6
+        kwargs['cutoff'] = max(5*debye_length,25)
+
+        if 'decompPeriod' not in kwargs:
+            kwargs['decompPeriod'] = 1000
+
+        """ Assign sequences """
+        if sequences is None:
+            raise NotImplementedError("OnckModel must be provided a sequences argument")
+
+        self.polymer_group = AbstractPolymerGroup(polymers)
+        self.sequences = sequences
+        ArbdModel.__init__(self, [], **kwargs)
+
+        """ Update type diffusion coefficients """
+        self.types = all_types = [t for key,t in _types.items()]
+        self.set_damping_coefficient( damping_coefficient )
+
+        """ Set up nonbonded interactions """
+        nonbonded = OnckNonbonded(debye_length)
+        for i in range(len(all_types)):
+            t1 = all_types[i]
+            for j in range(i,len(all_types)):
+                t2 = all_types[j]
+                self.useNonbondedScheme( nonbonded, typeA=t1, typeB=t2 )
+                
+        """ Generate beads """
+        self.generate_beads()
+
+    def update_splines(self, coords):
+        i = 0
+        for p in self.polymer_group.polymers:
+            n = p.num_monomers
+            p.set_splines(np.linspace(0,1,n), coords[i:i+n])
+            i += n
+
+        self.clear_all()
+        self.generate_beads()
+        ## TODO Apply restraints, etc
+
+    def generate_beads(self):
+        self.peptides = [OnckBeadsFromPolymer(p,s)
+                         for p,s in zip(self.polymer_group.polymers,self.sequences)]
+
+        for s in self.peptides:
+            self.add(s)
+            s._generate_beads()
+
+    def set_damping_coefficient(self, damping_coefficient):
+        for t in self.types:
+            t.damping_coefficient = damping_coefficient
+            # t.diffusivity = 831447.2 * temperature / (t.mass * damping_coefficient)
+
+if __name__ == "__main__":
+
+    print("TYPES")
+    for n,t in _types.items():
+        print("{}\t{}\t{}\t{}\t{}".format(n, t.name, t.mass, t.charge, t.epsilon))